Codapult ships both application infrastructure modules and deployment templates. You can start with Vercel, run the app in Docker, or self-host on AWS/Kubernetes using the included IaC.
Deployment & IaC
| Guide | What it covers |
|---|---|
| Self-Hosting | End-to-end production checklist for running Codapult outside Vercel |
| Docker | Dockerfile, docker-compose.yml, local containers, production images, and env vars |
| Terraform & Pulumi | AWS VPC, ECR, ECS Fargate, ALB, S3, SSM, CloudWatch, TLS, and DNS |
| Kubernetes | Helm chart structure, values.yaml, secrets, workers, Redis, ingress, HPA |
The IaC templates intentionally keep the database provider external: use Turso/libSQL, managed PostgreSQL (Neon, Supabase, RDS), or another provider supported by your DB_PROVIDER configuration.
Runtime Modules
Codapult also ships three infrastructure modules - file storage, background jobs, and notifications - each using the adapter pattern. Switch implementations via a single environment variable; no code changes required.
File Storage
Upload and serve files through a unified API with local, S3, or Cloudflare R2 adapters. See the dedicated File Storage documentation for provider setup, env vars, and programmatic usage.
Background Jobs
Offload work to background jobs with in-memory or BullMQ (Redis) adapters. See the dedicated Background Jobs documentation for job types, cron schedules, and production setup.
For production self-hosting, run web processes with JOB_PROVIDER="bullmq" and a Redis URL. If you deploy a dedicated worker, set CODAPULT_WORKER_MODE="true" on that worker and CODAPULT_DISABLE_IN_PROCESS_JOBS="true" on web pods/processes.
Notifications
In-app notifications with real-time delivery. The transport is selected by NOTIFICATION_TRANSPORT.
| Transport | Env Value | Description |
|---|---|---|
| Polling | poll (default) | Periodic HTTP requests — works everywhere, zero config |
| Server-Sent Events | sse | One-way real-time stream from server to client |
| WebSocket | ws | Full-duplex real-time — requires a separate WS server |
Dashboard Integration
The NotificationBell component in the dashboard header shows unread count and a dropdown list. It works with all three transports automatically.
Creating Notifications
import { createNotification } from '@/lib/notifications';
await createNotification({
userId: 'user_abc',
type: 'info', // 'info' | 'success' | 'warning' | 'error'
title: 'Deployment complete',
message: 'Your app was deployed to production.',
link: '/dashboard/deployments/42',
});
Operations
| Function | Description |
|---|---|
createNotification() | Create and deliver a notification |
getUserNotifications() | List notifications (newest first) |
getUnreadCount() | Count unread notifications |
markAsRead() | Mark a single notification as read |
markAllAsRead() | Mark all notifications as read |
WebSocket Configuration
When using the ws transport, configure the WebSocket server URL and port:
NOTIFICATION_TRANSPORT="ws"
NEXT_PUBLIC_WS_URL="ws://localhost:3001"
WS_PORT="3001"
Choosing a Transport
- Polling — simplest option, no infrastructure dependencies. Good for low-traffic apps.
- SSE — real-time without extra servers. One-way (server → client). Good default for production.
- WebSocket — full-duplex, lowest latency. Requires running a separate WS server process.