---
title: Deploying
description: Build, ship, and run your project on CoDuck infrastructure.
category: projects
order: 2
agent: "'coduck deploy' builds and runs the project. 'coduck stop', 'coduck restart', 'coduck status', 'coduck logs --follow'. One Docker container per project on CoDuck's VPS, running with --network=host (so localhost inside the container IS the host's loopback). Container reachable at .coduck.app subdomain unless a custom domain is attached. Instance sizes: small (1 CPU / 1.5 GB), medium (2 CPU / 2.5 GB), large (3 CPU / 4 GB). See /docs/reference/runtime for the full runtime architecture (DB ports, networking, filesystem)."
---

# Deploying

A deploy is when your project's code stops being a folder and becomes a live container with a public URL. CoDuck handles Docker image building, Postgres provisioning, migration runs, nginx + TLS, and starting the container. First deploy takes ~30–60 seconds; redeploys are ~10 seconds.

## Deploy from the dashboard

Open `https://app.coduck.ai/project/<projectId>`, switch to the **Cloud panel → Hosting tab → Deploys sub-tab**, and click **Deploy**. Watch progress in the **Logs** tab (tabbed alongside Hosting in the Cloud panel).

> [!TIP]
> Keep the Logs tab open in another window while deploying. Build and runtime errors stream there in real time and surface faster than the deploy status will.

## What happens during a deploy

Every command comes from your [`coduck.json`](/docs/reference/coduck-json), which is
**re-read on every deploy** — edit it, `coduck push`, `coduck deploy`, and the new
commands run. Each phase streams to the Logs tab live:

1. **Install** — your `install` command, or `npm install --include=dev --no-audit --no-fund` by default.
2. **Prisma generate** — only if `prisma/schema.prisma` declares models.
3. **Build** — your `build` command, or `npm run build` by default. Set `"build": ""` to skip.
4. **Schema bootstrap / pre-start** — if you have a Prisma schema with models and **no** `preStart`, CoDuck runs `prisma db push`. If you set a `preStart` (e.g. `prisma migrate deploy`), that runs instead and you own schema setup.
5. **Start** — your `start` command, or `npm start` by default. nginx is then reconfigured to route traffic to the container.

The base image is Node 20 by default; Node 22 and static-site runtimes are available via `runtime` in `coduck.json`.

See the [`coduck.json` reference](/docs/reference/coduck-json) for the full schema and field semantics.

## Instance size (resources)

Containers come in three tiers. Default is `small`; pick a bigger one with
`coduck deploy --size medium|large` or `"instanceSize"` in `coduck.json`.

| 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 |

The Node build-heap ceiling auto-scales with the tier, so heavy client builds that
OOM on `small` (three.js, remotion, recharts) usually succeed on `large`. A request
above your plan is clamped down, and the deploy tells you.

Other limits: restart policy **on-failure** (2 retries), runs as non-root (**uid
1001**), working directory **/app**.

## Environment variables

Manage env vars in **Cloud panel → Hosting → Env sub-tab**. You can set, view (masked by default), update, and delete values. Changes take effect on the **next deploy**.

A set of keys are reserved — CoDuck injects them on every deploy and rejects them
on write. They include `DATABASE_URL`, `DIRECT_URL`, `PORT`, `NODE_ENV`, and
everything under `CODUCK_*` / `NEXT_PUBLIC_CODUCK_*`. The full, authoritative list
is `coduck env reserved`; see the [`coduck.json` reference](/docs/reference/coduck-json#reserved-environment-variables).
Stripe keys are reserved only once you connect Stripe.

`coduck env import .env` skips reserved/invalid keys (with a warning) and imports
the rest — a `.env` containing `DATABASE_URL` won't abort the whole import.

## Stop, restart, tear down

In **Cloud panel → Hosting → Deploys sub-tab** you have three controls:

- **Stop** — stops the container. The database, URL, and env vars are preserved.
- **Restart** — restarts the container with the same config and a fresh runtime state.
- **Destroy** — removes the container, deletes the project's Postgres database, and removes the nginx vhost. **Irreversible** — take a backup first if you need the data.

## Custom domains and TLS

Once deployed, your project is reachable at `<project>.coduck.app` over HTTPS — nginx and a Let's Encrypt certificate are set up automatically on the first deploy. To attach your own domain, see [Custom domains](/docs/domains/custom-domains).

## Reading logs

Open **Cloud panel → Logs tab**, or from the CLI: `coduck logs --follow`, with
`--since 30m` and `--grep <pattern>` to narrow down. `coduck logs-digest` summarizes
errors/warnings.

## When a deploy fails

A failed deploy reports the specific cause (not a generic crash):

- **"out of memory …"** — the build or app exceeded the instance's RAM. Retry on a
  bigger tier: `coduck deploy --size large` (or `medium`). Moving asset compilation
  / codegen into the build step also helps.
- **"the build failed …"** — fix the error shown in the logs and redeploy. A common
  cause is a build-time package living in `devDependencies` — make sure your install
  step includes dev deps (the default does).
- **"responding on :3000 but health-checking :<port> …"** — your app hardcodes a
  port. Listen on `process.env.PORT` instead.
- **"the app crashed after starting …"** — the start command exited; check
  `coduck logs`. Usually a missing env var or a failed DB connection (remember the
  [database starts empty](/docs/database/overview) — run migrations in `preStart`).

## For developers

There's also a CLI (`@coduckai/cli`) for deploying from your terminal or from CI. See [CLI commands](/docs/cli/commands).

## Next

- [Custom domains](/docs/domains/custom-domains) — attach `example.com` to your project.
- [Database overview](/docs/database/overview) — what `DATABASE_URL` points at, and how to work with it.
