Codapult is self-hostable. The app builds as a standalone Next.js container and includes templates for Docker Compose, AWS ECS Fargate, Terraform, Pulumi, and Kubernetes/Helm.
Production Shape
| Layer | Recommended option | Included template |
|---|---|---|
| Web app | Standalone Next.js container | Dockerfile, docker-compose.yml, Helm deployment, ECS service |
| Database | Turso/libSQL or managed PostgreSQL | External provider configured by env vars |
| Secrets | Platform env vars, AWS SSM, or Kubernetes Secret | Terraform/Pulumi SSM, Helm existingSecret |
| File storage | S3 or Cloudflare R2 | S3 bucket in Terraform/Pulumi, S3-compatible adapter in app |
| Jobs | BullMQ + Redis for production | Helm worker + Redis, Docker Compose profile |
| Realtime | Polling, SSE, or WebSocket server | scripts/ws-server.ts, Docker Compose ws service |
| Observability | Sentry, OpenTelemetry, CloudWatch | App config plus AWS log group |
Required Environment
At minimum, production needs:
NEXT_PUBLIC_APP_URL="https://app.example.com"
NEXT_PUBLIC_APP_NAME="Your App"
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="..."
Add provider-specific variables for email, AI, SSO, storage, monitoring, and jobs. The full reference is in Environment Variables.
Build Once, Run Anywhere
docker build -t ghcr.io/acme/codapult:latest .
docker run --env-file .env.production -p 3000:3000 ghcr.io/acme/codapult:latest
The production image runs node server.js from Next.js standalone output. It does not need source files at runtime.
Database Choices
Codapult supports:
| Provider | Env |
|---|---|
| Turso/libSQL | DB_PROVIDER="turso", TURSO_DATABASE_URL, TURSO_AUTH_TOKEN |
| PostgreSQL | DB_PROVIDER="postgres", DATABASE_URL |
The AWS IaC does not create a database. This keeps the template portable across Turso, Neon, Supabase, RDS, Railway, and private PostgreSQL deployments.
Workers and Cron Jobs
For single-process deployments, the default JOB_PROVIDER="memory" starts in-process jobs. For production, use Redis-backed BullMQ:
JOB_PROVIDER="bullmq"
REDIS_URL="redis://redis:6379"
JOB_QUEUE_NAME="codapult"
If web and worker processes are separate:
# Web process
JOB_PROVIDER="bullmq"
CODAPULT_DISABLE_IN_PROCESS_JOBS="true"
# Worker process
JOB_PROVIDER="bullmq"
CODAPULT_WORKER_MODE="true"
The worker registers built-in handlers for email, webhook retries, monthly credit reset, RAG indexing, drip campaigns, scheduled reports, and cleanup jobs.
Storage
For production uploads, set:
STORAGE_PROVIDER="s3"
S3_BUCKET="your-bucket"
S3_REGION="us-east-1"
S3_ACCESS_KEY_ID="..."
S3_SECRET_ACCESS_KEY="..."
S3_PUBLIC_URL="https://cdn.example.com"
Use STORAGE_PROVIDER="r2" with an S3-compatible Cloudflare R2 endpoint. See File Storage.
Deployment Options
- Use Docker for a simple VM, Docker Compose, or any container platform.
- Use Terraform & Pulumi for AWS ECS Fargate.
- Use Kubernetes for any cluster with Helm support.
Production Checklist
-
NEXT_PUBLIC_APP_URLuses the final HTTPS domain. - Database migrations are applied with
pnpm db:migrateorpnpm db:push. -
BETTER_AUTH_SECRETis at least 32 characters and stored as a secret. - Webhooks are configured for the selected payment provider.
- Email sender domain is verified in Resend.
- S3/R2 storage is configured for uploads if local disk is not persistent.
- BullMQ + Redis is configured for multi-instance jobs.
- Sentry and OpenTelemetry are configured for production monitoring.
- Security headers and CSP are enabled through the default Next.js/proxy configuration.