#coduck.json reference
coduck.json is the source of truth for how CoDuck builds and runs your project.
coduck create-existing writes it; you can edit it by hand. It is re-read on
every deploy — change a command, coduck push, coduck deploy, and the new
command runs. (Earlier behavior baked config at create-time; that is no longer
the case.)
{
"projectId": "ff0c35e6-…", // set by create-existing; don't change
"name": "my-app",
"dir": "./", // source root to push + run (see "Monorepos")
"runtime": "node20", // node20 | node22 | static
"install": "npm ci", // optional — default: npm install --include=dev
"build": "npm run build", // optional — default: npm run build
"preStart": "npm run migrate", // optional — runs after build, before start
"start": "node server.js", // optional — default: npm start
"port": 3000, // informational; bind process.env.PORT (see below)
"instanceSize": "small" // small | medium | large
}{
"projectId": "ff0c35e6-…", // set by create-existing; don't change
"name": "my-app",
"dir": "./", // source root to push + run (see "Monorepos")
"runtime": "node20", // node20 | node22 | static
"install": "npm ci", // optional — default: npm install --include=dev
"build": "npm run build", // optional — default: npm run build
"preStart": "npm run migrate", // optional — runs after build, before start
"start": "node server.js", // optional — default: npm start
"port": 3000, // informational; bind process.env.PORT (see below)
"instanceSize": "small" // small | medium | large
}#How each field drives the deploy
A deploy runs these steps in order, in your container:
- install — your
install, elsenpm install --include=dev --no-audit --no-fund. (Dev deps are installed by default because build tools like Tailwind/PostCSS live there. If you override withnpm ci, noteNODE_ENV=productionis set, so add--include=devyourself if your build needs dev deps.) - prisma generate — only if
prisma/schema.prismaexists and declaresmodels. Skipped otherwise. - build — your
build, elsenpm run build. - schema bootstrap — if
prisma/schema.prismadeclares models and you have nopreStart, CoDuck runsprisma db push. If you setpreStart, CoDuck does not auto-push — you own schema setup (see Database). - preStart — your
preStart(e.g.prisma migrate deploy,drizzle-kit push,node scripts/migrate.js). The right place for migrations. - start — your
start, elsenpm start.
Skip a step by setting it to "" (empty string). E.g. a static/no-build app:
"build": "".
#Ports — bind process.env.PORT
CoDuck assigns the port and injects it as PORT. Your app must listen on
process.env.PORT, not a hardcoded value. The port field in coduck.json is
informational only — if your app hardcodes 3000 but CoDuck health-checks the
assigned port, the deploy fails with "responding on :3000 but health-checking
:
#Instance size
instanceSize (or coduck deploy --size) selects container resources. The CLI
flag wins; otherwise coduck.json is used; default small.
| Size | Memory | CPU | Plan required |
|---|---|---|---|
small | 1.5 GB | 1.0 | any paid plan |
medium | 2.5 GB | 2.0 | Pro or Studio |
large | 4 GB | 3.0 | Studio |
A request above your plan is clamped down (and the deploy tells you). The Node
build-heap ceiling auto-scales to ~80% of the tier, so heavy client builds
(three.js, remotion, recharts) that OOM on small usually succeed on large.
#Monorepos / subdirectory source
dir can point at a subdirectory (e.g. "./web") while coduck.json stays at the
repo root. The CLI uploads the repo-root coduck.json (and root
.gitignore/.coduckignore) alongside the subtree so the server still sees your
config. This requires @coduckai/cli ≥ 0.1.11 — older CLIs pushing a subdir
silently omitted coduck.json, so declared commands were ignored. Run
coduck --version and upgrade if needed.
One CoDuck project = one container. For a separate frontend + backend, wrap them
in a single start (e.g. concurrently) or create two projects.
#Reserved environment variables
CoDuck injects these into every container and rejects them on write (setting
them has no effect — platform values win). The live, authoritative list is
coduck env reserved.
| Key / pattern | What it is |
|---|---|
DATABASE_URL | Pooled Postgres connection string (see Database). |
DIRECT_URL | Direct (non-pooled) Postgres URL for migrations/prisma db push. |
PORT | The port to listen on. Bind process.env.PORT. |
NODE_ENV | Set to production in the container. |
HOME | Container home dir. |
CODUCK_* | All CoDuck-managed keys (CODUCK_API_KEY, CODUCK_AUTH_KEY, CODUCK_PROJECT_ID, CODUCK_API_URL, CODUCK_STORAGE_DIR, …). |
NEXT_PUBLIC_CODUCK_* | Browser-exposed CoDuck values (project id, auth/api URLs, subdomain). |
Stripe keys (STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY,
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY) are injected only when you connect
Stripe — until then you may set them yourself.
coduck env import .env skips reserved/invalid keys with a warning and imports
the rest, so a .env containing DATABASE_URL won't abort the whole import.
#Next
- Deploying — the deploy lifecycle + failure messages.
- Import an existing project
- Database — the managed Postgres starts empty.