Codapult includes a multi-stage Dockerfile and docker-compose.yml for local containers, production images, and optional WebSocket notifications.
Dockerfile
The production image has three stages:
| Stage | Purpose |
|---|---|
deps | Enables Corepack, installs dependencies with pnpm install --frozen-lockfile |
builder | Copies the app, sets build-time defaults, and runs pnpm run build |
runner | Runs the Next.js standalone server as the unprivileged nextjs user |
The final image exposes port 3000 and starts:
node server.js
Because next.config.ts uses output: "standalone", the image only needs .next/standalone, .next/static, and public.
Build
docker build -t codapult:latest .
Run
docker run --env-file .env.production -p 3000:3000 codapult:latest
Use a production env file. Do not bake secrets into the image.
Docker Compose
docker-compose.yml defines three services:
| Service | Purpose |
|---|---|
app | Production build using the project Dockerfile |
dev | Hot-reload development container with source mounted into /app |
ws | Optional WebSocket notification server for NOTIFICATION_TRANSPORT="ws" |
Start the production container:
docker compose up app
Start development mode:
docker compose up dev
Start WebSocket notifications:
docker compose --profile ws up ws
Environment
Both app and dev read .env.local by default. For production, point Compose or your platform to a separate secret source.
Common container variables:
NEXT_PUBLIC_APP_URL="https://app.example.com"
NEXT_PUBLIC_APP_NAME="Codapult"
DB_PROVIDER="turso"
TURSO_DATABASE_URL="libsql://..."
TURSO_AUTH_TOKEN="..."
AUTH_PROVIDER="better-auth"
BETTER_AUTH_SECRET="..."
PAYMENT_PROVIDER="stripe"
STRIPE_SECRET_KEY="..."
STRIPE_WEBHOOK_SECRET="..."
Jobs
For a single container, use the default in-process memory jobs:
JOB_PROVIDER="memory"
For production queues:
JOB_PROVIDER="bullmq"
REDIS_URL="redis://redis:6379"
If a separate worker container handles jobs, set CODAPULT_WORKER_MODE="true" on the worker and CODAPULT_DISABLE_IN_PROCESS_JOBS="true" on web containers.
WebSocket Notifications
The ws Compose profile runs scripts/ws-server.ts with WS_PORT=3001.
NOTIFICATION_TRANSPORT="ws"
NEXT_PUBLIC_WS_URL="ws://localhost:3001"
WS_PORT="3001"
Use polling or SSE when you do not need a separate WebSocket process.