Environment Variables Reference
Doable reads configuration from a .env file (loaded by Node) and from process environment variables. The same variables apply across local development, bare-metal, and Docker — only the source file location differs:
- Local dev / bare-metal:
.env in the repo root.
- Docker:
docker/.env.
Anything prefixed NEXT_PUBLIC_ is inlined into the client bundle at build time. Don't put secrets in NEXT_PUBLIC_*.
Required
| Variable |
Description |
How to generate |
JWT_SECRET |
HMAC key for access/refresh JWTs |
openssl rand -hex 32 |
ENCRYPTION_KEY |
AES key for encrypting OAuth tokens, integration credentials, etc. |
openssl rand -hex 32 |
INTERNAL_SECRET |
Shared secret between API ↔ WS for trusted internal calls |
openssl rand -hex 32 |
DATABASE_URL |
PostgreSQL connection string |
postgres://user:pass@host:5432/db |
The Docker compose file refuses to start if any of the three secrets are missing.
Database
| Variable |
Default |
Notes |
DATABASE_URL |
— |
Required |
DATABASE_POOL_SIZE |
20 |
Max connections per process |
API server
| Variable |
Default |
Notes |
API_PORT |
4000 |
|
API_HOST |
127.0.0.1 |
Must stay 127.0.0.1 in production — see Network Binding. Docker overrides to 0.0.0.0 because the container is the security boundary. |
CORS_ORIGINS |
http://localhost:3000 |
Comma-separated list of allowed origins |
API_URL |
http://localhost:4000 |
URL the WS process uses to call the API |
JWT_ISSUER |
doable |
|
JWT_ACCESS_TOKEN_EXPIRES_IN |
15m |
ms-style duration |
JWT_REFRESH_TOKEN_EXPIRES_IN |
7d |
|
WebSocket server
| Variable |
Default |
Notes |
WS_PORT |
4001 |
|
WS_HOST |
127.0.0.1 |
Same rule as API_HOST |
WS_INTERNAL_URL |
http://localhost:4001 |
URL the API uses to call the WS |
Frontend (Next.js)
| Variable |
Default |
Notes |
NEXT_PUBLIC_API_URL |
http://localhost:4000 |
Public-facing API URL |
NEXT_PUBLIC_WS_URL |
ws://localhost:4001 |
Public-facing WS URL |
NEXT_PUBLIC_APP_URL |
http://localhost:3000 |
The app's own canonical URL |
AI providers
Configure at least one for the chat agent to work.
| Variable |
Provider |
Notes |
ANTHROPIC_API_KEY |
Claude |
Recommended for highest-quality codegen |
OPENAI_API_KEY |
OpenAI |
GPT-4-class models |
COPILOT_CLI_PATH |
GitHub Copilot SDK |
Path to the copilot binary |
COPILOT_CLI_URL |
GitHub Copilot SDK |
Use a remote Copilot CLI server instead of spawning one |
COPILOT_DEFAULT_MODEL |
both Copilot paths |
Model name to default to |
Per-workspace overrides can be set in Workspace Settings → AI and live in the database — these env vars are only the global defaults. See AI Providers.
OAuth
| Variable |
Default |
Notes |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET |
— |
Login with GitHub |
GITHUB_REDIRECT_URI |
http://localhost:4000/auth/github/callback |
|
GITHUB_COPILOT_REDIRECT_URI |
http://localhost:4000/auth/github/copilot/callback |
OAuth flow used when the user opts to use their own Copilot account |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
— |
Login with Google |
GOOGLE_REDIRECT_URI |
http://localhost:4000/auth/google/callback |
|
See .env.integrations.example for the OAuth provider catalog (Slack, Notion, Linear, etc.).
Storage (S3-compatible)
Optional — needed only if you let users upload assets.
| Variable |
Default |
Notes |
S3_BUCKET |
doable-uploads |
Bucket name |
S3_REGION |
us-east-1 |
|
S3_ACCESS_KEY / S3_SECRET_KEY |
— |
IAM credentials |
S3_ENDPOINT |
— |
Set for non-AWS S3 (R2, MinIO, etc.) |
Stripe
Optional — needed only if you charge for plans/credits.
| Variable |
Notes |
STRIPE_SECRET_KEY |
Server-side secret |
STRIPE_WEBHOOK_SECRET |
Verify webhook signatures |
STRIPE_PRO_MONTHLY_PRICE_ID / STRIPE_PRO_YEARLY_PRICE_ID |
Pro plan |
STRIPE_BUSINESS_MONTHLY_PRICE_ID / STRIPE_BUSINESS_YEARLY_PRICE_ID |
Business plan |
Publishing & custom domains
| Variable |
Default |
Notes |
PROJECTS_ROOT |
./services/api/projects |
Where user project files live on disk |
SITES_DIR |
./sites |
Where built static sites are placed |
DOABLE_DOMAIN |
localhost |
Subdomain suffix for published projects (<slug>.doable.me) |
CLOUDFLARE_TUNNEL_ID |
— |
UUID of the Cloudflare Tunnel that routes published sites |
CADDYFILE_PATH |
/etc/caddy/Caddyfile |
Where the publish flow appends per-domain blocks |
See Custom Domains.
Redis (optional)
| Variable |
Default |
Notes |
REDIS_URL |
empty (in-memory) |
Set to enable shared rate-limiting & sessions |
Misc
| Variable |
Default |
Notes |
NODE_ENV |
development |
production enables prod optimizations |
See also