Appearance
Environment Variable Reference
All environment variables are validated at startup using Zod. If a required variable is missing or invalid, the server refuses to start with a clear error message.
Configuration is loaded from a .env file (via dotenv) and then validated against the schema in src/env.ts.
Database
| Variable | Default | Required | Description |
|---|---|---|---|
DB_CLIENT | pg | No | Database driver: pg, mysql, mysql2, sqlite3, better-sqlite3 |
DB_HOST | localhost | No | Database host |
DB_PORT | 5432 | No | Database port |
DB_DATABASE | cms | No | Database name |
DB_USER | odp_user | No | Database user |
DB_PASSWORD | `` | No | Database password |
DB_SSL | false | No | Enable SSL connection |
DB_POOL_MIN | 0 | No | Min connection pool size |
DB_POOL_MAX | 10 | No | Max connection pool size |
DB_FILENAME | — | No | SQLite database file path (SQLite only) |
Server
| Variable | Default | Required | Description |
|---|---|---|---|
HOST | 0.0.0.0 | No | Bind address |
PORT | 8055 | No | HTTP port |
PUBLIC_URL | http://localhost:8055 | No | Publicly accessible base URL |
SECRET | — | Yes | JWT signing secret (min 1 character) |
ACCESS_TOKEN_TTL | 15m | No | Access token lifetime (e.g., 15m, 1h) |
REFRESH_TOKEN_TTL | 7d | No | Refresh token lifetime (e.g., 7d, 30d) |
SESSION_COOKIE_ENABLED | true | No | Enable session cookie mode |
SESSION_COOKIE_NAME | odp_session_token | No | Cookie name for session tokens |
LOG_LEVEL | info | No | trace, debug, info, warn, error, fatal |
LOG_STYLE | pretty | No | pretty (colored output) or raw (JSON) |
LOG_FILE | — | No | Path to write logs to a file |
LOG_REQUESTS | true | No | Log each HTTP request |
MAX_PAYLOAD_SIZE | 1mb | No | Maximum request body size |
ROOT_REDIRECT | /server/info | No | Where / redirects to |
NODE_ENV | development | No | development, production, test |
CORS
| Variable | Default | Description |
|---|---|---|
CORS_ENABLED | true | Enable CORS headers |
CORS_ORIGIN | * | Allowed origins (comma-separated or *) |
CORS_METHODS | GET,POST,PATCH,DELETE | Allowed HTTP methods |
CORS_ALLOWED_HEADERS | Content-Type,Authorization | Allowed request headers |
CORS_EXPOSED_HEADERS | Content-Range | Exposed response headers |
CORS_CREDENTIALS | true | Allow credentials |
CORS_MAX_AGE | 18000 | Preflight cache duration (seconds) |
Cache
| Variable | Default | Description |
|---|---|---|
CACHE_ENABLED | false | Enable response caching |
CACHE_TTL | 5m | Cache entry lifetime |
CACHE_STORE | memory | Backend: memory or redis |
CACHE_AUTO_PURGE | false | Auto-invalidate on mutations |
CACHE_SCHEMA | true | Cache database schema |
CACHE_SYSTEM_TTL | 10m | System cache TTL |
CACHE_NAMESPACE | odp | Cache key prefix |
CACHE_STATUS_HEADER | x-cache-status | Response header for cache status |
CACHE_VALUE_MAX_SIZE | 1mb | Maximum cacheable response size |
Redis
| Variable | Default | Description |
|---|---|---|
REDIS_ENABLED | false | Use Redis for cache and sessions |
REDIS_HOST | 127.0.0.1 | Redis host |
REDIS_PORT | 6379 | Redis port |
REDIS_PASSWORD | `` | Redis password |
REDIS_DB | 0 | Redis database index |
Storage & Files
| Variable | Default | Description |
|---|---|---|
STORAGE_LOCAL_ROOT | ./uploads | Local file storage directory |
FILES_MAX_UPLOAD_SIZE | 10mb | Maximum upload size per file |
FILES_MIME_TYPE_ALLOW_LIST | * | Allowed MIME types (* = all, or comma-separated list) |
FILES_MAX_UPLOAD_CONCURRENCY | 5 | Max simultaneous file uploads |
Image Transformation (Assets)
| Variable | Default | Description |
|---|---|---|
ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION | 6000 | Max output width or height (pixels) |
ASSETS_TRANSFORM_MAX_CONCURRENT | 25 | Max concurrent image transforms |
ASSETS_TRANSFORM_TIMEOUT | 30 | Transform timeout (seconds) |
ASSETS_CACHE_TTL | 30m | Transformed asset cache TTL |
ASSETS_INVALID_IMAGE_SENSITIVITY_LEVEL | warning | How to handle corrupt images: none, truncated, error, warning |
Email
| Variable | Default | Description |
|---|---|---|
EMAIL_FROM | no-reply@example.com | Default sender address |
EMAIL_TRANSPORT | smtp | Transport: smtp, ses, sendmail |
EMAIL_SMTP_HOST | localhost | SMTP server host |
EMAIL_SMTP_PORT | 587 | SMTP port |
EMAIL_SMTP_USER | `` | SMTP username |
EMAIL_SMTP_PASSWORD | `` | SMTP password |
EMAIL_SMTP_SECURE | false | Enable TLS/SSL |
Rate Limiting
| Variable | Default | Description |
|---|---|---|
RATE_LIMITER_ENABLED | true | Enable per-IP rate limiting |
RATE_LIMITER_STORE | memory | Store: memory or redis |
RATE_LIMITER_POINTS | 50 | Max requests per window |
RATE_LIMITER_DURATION | 1 | Window duration (seconds) |
RATE_LIMITER_GLOBAL_ENABLED | true | Enable global (all-IP) rate limit |
RATE_LIMITER_GLOBAL_POINTS | 1000 | Global requests per window |
RATE_LIMITER_GLOBAL_DURATION | 1 | Global window duration (seconds) |
Authentication Throttling
| Variable | Default | Description |
|---|---|---|
LOGIN_THROTTLE_DELAY | 1s | Initial delay after failed login |
LOGIN_THROTTLE_MAX_DELAY | 30s | Maximum backoff delay |
WebSocket
| Variable | Default | Description |
|---|---|---|
WEBSOCKETS_ENABLED | true | Enable WebSocket support |
WEBSOCKETS_HEARTBEAT_ENABLED | true | Enable ping/pong heartbeat |
WEBSOCKETS_HEARTBEAT_PERIOD | 30 | Heartbeat interval (seconds) |
WEBSOCKETS_REST_ENABLED | true | Enable REST-over-WebSocket |
WEBSOCKETS_REST_AUTH | handshake | Auth mode: public, handshake, strict |
WEBSOCKETS_GRAPHQL_ENABLED | true | Enable GraphQL over WebSocket |
WEBSOCKETS_GRAPHQL_AUTH | handshake | Auth mode: public, handshake, strict |
Extensions
| Variable | Default | Description |
|---|---|---|
EXTENSIONS_PATH | ./extensions | Directory to load extensions from |
EXTENSIONS_MUST_LOAD | `` | Comma-separated list of extensions that must load (server fails if missing) |
EXTENSIONS_AUTO_RELOAD | false | Watch and auto-reload extensions on change |
TUS Resumable Upload
| Variable | Default | Description |
|---|---|---|
TUS_UPLOAD_EXPIRATION | 10m | Expiry for incomplete TUS uploads |
TUS_CLEANUP_SCHEDULE | 0 */6 * * * | Cron schedule for TUS cleanup job |
Miscellaneous
| Variable | Default | Description |
|---|---|---|
MIGRATIONS_PATH | `` | Path to custom migration files |
PRESSURE_ENABLED | true | Enable server load shedding |
METRICS_ENABLED | false | Expose Prometheus metrics endpoint |
METRICS_NAME_PREFIX | odp_ | Prometheus metric name prefix |
USER_INVITE_TOKEN_TTL | 7d | Invite token lifetime |
QUERYSTRING_MAX_PARSE_DEPTH | 10 | Max nesting depth for query string parsing |
Example .env
env
# Required
SECRET=your-super-secret-key-change-in-production
# Database
DB_CLIENT=pg
DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=odp
DB_USER=odp_user
DB_PASSWORD=odp_password
# Server
PORT=8055
PUBLIC_URL=https://api.example.com
LOG_LEVEL=info
LOG_STYLE=raw
# Cache (Redis)
CACHE_ENABLED=true
CACHE_STORE=redis
REDIS_ENABLED=true
REDIS_HOST=redis
REDIS_PORT=6379
# Email
EMAIL_FROM=no-reply@example.com
EMAIL_TRANSPORT=smtp
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USER=smtp-user
EMAIL_SMTP_PASSWORD=smtp-password
EMAIL_SMTP_SECURE=true
# Storage
STORAGE_LOCAL_ROOT=/data/uploads
FILES_MAX_UPLOAD_SIZE=50mb
# Security
RATE_LIMITER_ENABLED=true
SESSION_COOKIE_ENABLED=true