This guide gets a local cnode-next workspace running. It is not a production deployment guide; production compose and dotenv templates live in deployment/.
| Requirement | Version or rule |
|---|---|
| Node.js | >= 24.0.0 |
| pnpm | Managed by packageManager and Corepack. |
| PostgreSQL | Required. SQLite is not supported. |
| Redis | Required for sessions, cache, rate limits, and worker paths. |
Copy the local template and fill development values:
cp .env.example .envRoot .env is the single default local environment source for Web, API, DB scripts, workers, and migration tooling. .env.local and app-local files such as apps/web/.env.local are not loaded by default. Do not commit or paste real .env values.
Minimum local values:
APP_ENV=development
APP_WEB_BASE_URL=http://localhost:5173
APP_API_BASE_URL=http://localhost:3001
APP_API_INTERNAL_BASE_URL=http://localhost:3001
DB_HOST=127.0.0.1
DB_PORT=5432
DB_NAME=cnode_local
DB_USER=cnode
DB_PASSWORD=<local-password>
REDIS_HOST=127.0.0.1
REDIS_PORT=6379Use any local PostgreSQL and Redis setup. Docker is fine, but do not use the production compose file for day-to-day development.
Example with standalone containers:
docker run --name cnode-postgres \
-e POSTGRES_DB=cnode_local \
-e POSTGRES_USER=cnode \
-e POSTGRES_PASSWORD=<local-password> \
-p 5432:5432 \
-d postgres:18-bookworm
docker run --name cnode-redis \
-p 6379:6379 \
-d redis:7-bookworm redis-server --appendonly yesIf you use an SSH tunnel to a private database for migration rehearsal, keep that configuration in an explicit ignored profile such as .env.remote.local, point DB_HOST and DB_PORT at the local tunnel listener, and run commands with CNODE_ENV_FILE=.env.remote.local. Do not expose databases publicly.
pnpm install
pnpm db:push:pg
pnpm devLocal endpoints:
| Service | URL |
|---|---|
| Web | http://localhost:5173 |
| API | http://localhost:3001 |
Quick smoke:
curl -fsS 'http://localhost:3001/api/v1/topics?limit=1&tab=all'
curl -fsS 'http://localhost:5173/'| Command | Use |
|---|---|
pnpm dev |
Start Web and API locally. |
pnpm lint |
Run oxlint. |
pnpm typecheck |
Run TypeScript checks across the workspace. |
pnpm test |
Run package tests. |
pnpm build |
Build all apps/packages. |
pnpm db:push:pg |
Create or update the PostgreSQL schema. |
pnpm db:seed |
Seed development data. |
pnpm migrate:mongo-to-pg |
Run explicit Mongo-to-PostgreSQL migration tooling. |
pnpm migrate:reconcile |
Reconcile migrated data. |
pnpm verify |
Full validation gate. Run before release or PR validation when feasible. |
Runtime commands keep their default command shape and load root .env from their natural config or script entrypoints. Explicit profiles override root .env values with CNODE_ENV_FILE, while shell/CI/compose-provided variables remain authoritative.
| Command | Local env behavior |
|---|---|
pnpm dev |
Keeps existing Web/API scripts; Web loads root .env from apps/web/vite.config.ts, API from apps/api/src/load-env.ts. |
pnpm --filter @cnode/web dev |
Keeps react-router dev; Vite config loads root .env. |
pnpm --filter @cnode/web build |
Keeps react-router build; Vite config loads root .env. |
pnpm --filter @cnode/web typecheck |
Keeps react-router typegen && tsc --noEmit; Vite config loads root .env for React Router typegen. |
pnpm --filter @cnode/api dev |
Keeps tsx watch src/index.ts; API runtime loader loads root .env. |
pnpm --filter @cnode/api worker:moderation |
Keeps worker command; API worker imports the runtime loader. |
pnpm db:push:pg, pnpm db:generate |
Keep drizzle-kit commands; Drizzle config loads root .env. |
pnpm db:migrate, pnpm db:seed |
Keep tsx src/* commands; DB scripts load root .env. |
pnpm migrate:mongo-to-pg, pnpm migrate:reconcile |
Keep root tsx scripts/* commands; scripts load root .env; use CNODE_ENV_FILE=.env.remote.local for remote rehearsal. |
pnpm lint, pnpm format, pnpm secrets:scan, pnpm verify:compose-config |
Do not load local dotenv files. |
Example remote rehearsal profile:
CNODE_ENV_FILE=.env.remote.local pnpm migrate:reconcileAPI contracts are defined in apps/api/src/routes/*.ts as zod-openapi declarations. Run pnpm gen:openapi to regenerate api/openapi.json. pnpm verify includes this step automatically.