- Docs
- Run in Production
- Environment Variables
Every environment variable, one page.
The complete environment variable reference for the bunqueue server and CLI: ports, storage, auth, TLS, S3 backup, timeouts, and logging.
Server & storage
Section titled “Server & storage”| Variable | Type | Default | Description |
|---|---|---|---|
TCP_PORT | number | 6789 | TCP server port for client connections |
HTTP_PORT | number | 6790 | HTTP server port for REST API and metrics |
HOST | string | 0.0.0.0 | Bind address (127.0.0.1 for local-only) |
BUNQUEUE_STORAGE_DRIVER | string | inferred | memory, sqlite, or postgres |
BUNQUEUE_DATA_PATH | string | (in-memory) | SQLite database path. Without it or a PostgreSQL URL, jobs are lost on restart |
BUNQUEUE_MAX_COMPLETED_JOBS | positive integer | 50000 | Completed-job hot cache/recovery window; does not delete durable rows |
BUNQUEUE_COMPLETED_RETENTION_MS | non-negative integer | disabled | Age after which the background cleanup may delete completed SQLite rows |
BUNQUEUE_POSTGRES_URL | string | (none) | PostgreSQL connection URL; implies the postgres driver when no driver is set |
BUNQUEUE_POSTGRES_NAMESPACE | string | default | Isolates independent bunqueue installations in one PostgreSQL database |
BUNQUEUE_BROKER_ID | string | generated | Stable unique ID for this PostgreSQL broker process |
BUNQUEUE_POSTGRES_POOL_SIZE | positive integer | 4 | PostgreSQL pool size (runtime minimum 2) |
BUNQUEUE_POSTGRES_LEASE_DURATION_MS | positive integer | 30000 | Default database-clock lease duration (runtime minimum 1000) |
BUNQUEUE_POSTGRES_POLL_INTERVAL_MS | positive integer | 250 | Event/cron fallback polling interval (runtime minimum 25) |
BUNQUEUE_POSTGRES_STATEMENT_TIMEOUT_MS | positive integer | 30000 | Maximum PostgreSQL statement duration |
BUNQUEUE_POSTGRES_LOCK_TIMEOUT_MS | positive integer | 5000 | Maximum wait for a PostgreSQL lock |
BUNQUEUE_POSTGRES_IDLE_TRANSACTION_TIMEOUT_MS | positive integer | 30000 | Maximum idle time inside a transaction |
BUNQUEUE_POSTGRES_MAX_CONCURRENT_OPERATIONS | positive integer | 16 | Active PostgreSQL manager operations per broker |
BUNQUEUE_POSTGRES_MAX_QUEUED_OPERATIONS | non-negative integer | 128 | Waiting PostgreSQL manager operations before fail-fast saturation |
BUNQUEUE_POSTGRES_MAX_SNAPSHOT_JOBS | positive integer | 100000 | Maximum job/result entities in one compatibility snapshot |
BUNQUEUE_POSTGRES_MAX_SNAPSHOT_PAYLOAD_BYTES | positive integer | 268435456 | Maximum encoded bytes in one compatibility snapshot |
HTTP_SOCKET_PATH | string | (none) | Unix socket for the HTTP server, replaces HTTP_PORT |
TCP_SOCKET_PATH | string | (none) | Reserved, not functional yet (see below) |
TLS_CERT_FILE | string | (none) | PEM certificate, enables native TLS on TCP + HTTP |
TLS_KEY_FILE | string | (none) | PEM private key matching TLS_CERT_FILE |
BUNQUEUE_DATA_PATH=/var/lib/queue.db TCP_PORT=6789 bunqueue startData path aliases. Four names are read for the SQLite path, in priority order: BUNQUEUE_DATA_PATH > BQ_DATA_PATH > DATA_PATH > SQLITE_PATH. They are equivalent; prefer BUNQUEUE_DATA_PATH.
Completed-job retention. BUNQUEUE_MAX_COMPLETED_JOBS (legacy alias:
MAX_COMPLETED_JOBS) only bounds the hot in-memory projection. Durable
retention is opt-in through BUNQUEUE_COMPLETED_RETENTION_MS (legacy alias:
COMPLETED_RETENTION_MS); when unset, completed SQLite rows are retained until
an explicit clean or obliterate operation. 0 makes every unprotected
completed row eligible on the next cleanup tick.
Storage selection. An explicit driver wins. Otherwise a PostgreSQL URL
selects PostgreSQL, a data path selects SQLite, and neither selects memory.
PostgreSQL and a SQLite data path cannot be combined. PostgreSQL is server-only,
tested in CI against majors 15, 16, 17, and the pinned/recommended 18.6 release,
and every active broker sharing a namespace must have a unique broker ID. MySQL
is not supported. In the repository Compose
topology, POSTGRES_PASSWORD configures the database and
BUNQUEUE_POSTGRES_URL configures brokers; if the secret contains URI-reserved
characters, percent-encode its password component in the URL.
BUNQUEUE_STORAGE_DRIVER=postgres \BUNQUEUE_POSTGRES_URL='postgres://bunqueue:secret@postgres:5432/bunqueue' \BUNQUEUE_POSTGRES_NAMESPACE=production \BUNQUEUE_BROKER_ID=broker-a \bunqueue startTLS. Set both TLS_CERT_FILE and TLS_KEY_FILE or neither, setting only one is a startup error (fail fast, never silent plaintext). See the TLS guide.
Authentication & security
Section titled “Authentication & security”| Variable | Type | Default | Description |
|---|---|---|---|
AUTH_TOKENS | string | (none) | Comma-separated tokens for every TCP connection and protected HTTP endpoint; health probes stay public |
BQ_TOKEN / BUNQUEUE_TOKEN | string | (none) | Default token for CLI client commands (avoids --token on every command) |
METRICS_AUTH | boolean | false | Require auth for /prometheus. Only true enables it; without AUTH_TOKENS, the endpoint returns 503 |
METRICS_MAX_QUEUES | integer | 100 | Maximum queue names exposed as Prometheus label values; 0 disables per-queue series |
CORS_ALLOW_ORIGIN | string | (none) | Comma-separated allowed CORS origins for the HTTP API |
# Server sideAUTH_TOKENS=secret-token-1,secret-token-2 bunqueue start
# Client side, every protected request must carry a tokenbunqueue push emails '{"to":"test@example.com"}' --token secret-token-1curl -H "Authorization: Bearer secret-token-1" http://localhost:6790/queues
# Or set it once for the CLI (priority: --token flag > BQ_TOKEN > BUNQUEUE_TOKEN)export BQ_TOKEN=secret-token-1bunqueue statsThe JSON /metrics endpoint is already covered by the general AUTH_TOKENS
check; METRICS_AUTH adds the same requirement to /prometheus. Enabling it
without configuring any token fails closed with 503.
Logging
Section titled “Logging”| Variable | Type | Default | Values |
|---|---|---|---|
LOG_LEVEL | string | info | debug, info, warn, error |
LOG_FORMAT | string | text | text, json |
LOG_LEVEL=debug LOG_FORMAT=json bunqueue startJSON output looks like:
{ "timestamp": "2024-01-15T10:30:00.000Z", "level": "info", "component": "Server", "message": "Received SIGTERM, shutting down..."}Structured fields appear nested under a data key; the startup banner itself
is plain text, not a JSON record.
S3 backup
Section titled “S3 backup”Automatic snapshots of the SQLite database to any S3-compatible storage. Full guide: S3 Backup.
| Variable | Type | Default | Description |
|---|---|---|---|
S3_BACKUP_ENABLED | boolean | false | Enable automated backups (1 / true) |
S3_BUCKET | string | (none) | Bucket name (alias: AWS_BUCKET) |
S3_ACCESS_KEY_ID | string | (none) | Access key (alias: AWS_ACCESS_KEY_ID) |
S3_SECRET_ACCESS_KEY | string | (none) | Secret key (alias: AWS_SECRET_ACCESS_KEY) |
S3_SESSION_TOKEN | string | (none) | Temporary credential token (alias: AWS_SESSION_TOKEN) |
S3_REGION | string | us-east-1 | Region (alias: AWS_REGION) |
S3_ENDPOINT | string | (none) | Custom endpoint for non-AWS providers (alias: AWS_ENDPOINT) |
S3_VIRTUAL_HOSTED_STYLE | boolean | provider default | Force bucket-in-host addressing (1 / true) |
S3_BACKUP_INTERVAL | number | 21600000 (6h) | Interval between backups in ms |
S3_BACKUP_RETENTION | number | 7 | Number of backups to keep |
S3_BACKUP_PREFIX | string | backups/ | Key prefix for backup files |
Backups require a persistent SQLite data path (BUNQUEUE_DATA_PATH,
BQ_DATA_PATH, DATA_PATH, or SQLITE_PATH). There is no file to snapshot in
in-memory mode, and the built-in snapshot facility does not back up PostgreSQL.
Enabling it without persistent SQLite fails server startup before binding
TCP/HTTP.
# Cloudflare R2S3_ENDPOINT=https://abc123.r2.cloudflarestorage.com S3_BACKUP_ENABLED=1 bunqueue start
# MinIOS3_ENDPOINT=http://localhost:9000 S3_BACKUP_ENABLED=1 bunqueue startTimeouts & limits
Section titled “Timeouts & limits”| Variable | Type | Default | Description |
|---|---|---|---|
SHUTDOWN_TIMEOUT_MS | number | 30000 | How long graceful shutdown waits for active jobs |
STATS_INTERVAL_MS | number | 300000 | Stats logging interval |
WORKER_TIMEOUT_MS | number | 30000 | Worker-registration freshness window. Older heartbeats mark a worker stale; cleanup removes it after 3× this value |
LOCK_TIMEOUT_MS | number | 5000 | Timeout for acquiring internal locks |
WORKER_CLEANUP_INTERVAL_MS | number | 60000 | Interval for removing inactive worker registrations |
TCP_IDLE_TIMEOUT_MS | number | 60000 | Slowloris mitigation: close a connection that starts a frame but makes no progress within this window. Idle connections with no partial frame are never affected. 0 disables |
TCP_MAX_WRITE_QUEUE_BYTES | number | 67108864 (64 MB) | Max bytes buffered per connection’s outbound queue before it is dropped (protects against clients that stop reading). 0 disables |
Webhooks
Section titled “Webhooks”| Variable | Type | Default | Description |
|---|---|---|---|
WEBHOOK_MAX_RETRIES | number | 3 | Max delivery retry attempts |
WEBHOOK_RETRY_DELAY_MS | number | 1000 | Delay between delivery retries |
Server rate limiting
Section titled “Server rate limiting”Protects the server itself from misbehaving clients (per TCP connection or HTTP client IP). Unrelated to per-queue job rate limiting, which is set via the Queue API.
| Variable | Type | Default | Description |
|---|---|---|---|
RATE_LIMIT_MAX_REQUESTS | number | 10000 | Max requests per client within the window |
RATE_LIMIT_WINDOW_MS | number | 60000 | Window duration |
RATE_LIMIT_CLEANUP_MS | number | 60000 | Cleanup interval for tracking data |
Monitoring thresholds
Section titled “Monitoring thresholds”These control the real-time monitoring events (queue:idle, queue:threshold, worker:overloaded, server:memory-warning, storage:size-warning) delivered over WebSocket/SSE. See the HTTP API events reference.
| Variable | Default | Description |
|---|---|---|
QUEUE_IDLE_THRESHOLD_MS | 30000 | Emit queue:idle when a queue is empty with no active jobs for this long. 0 disables |
QUEUE_SIZE_THRESHOLD | 0 (disabled) | Emit queue:threshold when a queue’s waiting count reaches this size |
WORKER_OVERLOAD_THRESHOLD_MS | 30000 | Emit worker:overloaded when a worker stays at max concurrency for this long |
MEMORY_WARNING_MB | 0 (disabled) | Emit server:memory-warning when heap usage exceeds this many MB |
STORAGE_WARNING_MB | 0 (disabled) | Emit storage:size-warning when the SQLite database exceeds this many MB |
bunqueue Cloud
Section titled “bunqueue Cloud”Telemetry agent for the bunqueue Cloud dashboard. Cloud mode activates only when BUNQUEUE_CLOUD_URL, BUNQUEUE_CLOUD_API_KEY, and BUNQUEUE_CLOUD_INSTANCE_ID are all set.
| Variable | Default | Description |
|---|---|---|
BUNQUEUE_CLOUD_URL | (none) | Cloud dashboard URL. Required for cloud mode |
BUNQUEUE_CLOUD_API_KEY | (none) | API key. Required for cloud mode |
BUNQUEUE_CLOUD_INSTANCE_ID | (none) | Unique instance identifier. Required for cloud mode |
BUNQUEUE_CLOUD_INSTANCE_NAME | hostname | Display name for this instance |
BUNQUEUE_CLOUD_SIGNING_SECRET | (none) | HMAC signing secret for payloads |
BUNQUEUE_CLOUD_INTERVAL_MS | 15000 | Snapshot upload interval in ms |
BUNQUEUE_CLOUD_INCLUDE_JOB_DATA | true | Include job payloads in telemetry. Set false for metadata only |
BUNQUEUE_CLOUD_REDACT_FIELDS | (none) | Comma-separated payload fields to redact |
BUNQUEUE_CLOUD_EVENTS | (all) | Comma-separated event filter |
BUNQUEUE_CLOUD_BUFFER_SIZE | 720 | Snapshot buffer size while offline |
BUNQUEUE_CLOUD_CIRCUIT_BREAKER_THRESHOLD | 5 | Consecutive failures before the circuit breaker opens |
BUNQUEUE_CLOUD_CIRCUIT_BREAKER_RESET_MS | 60000 | Circuit breaker reset window in ms |
BUNQUEUE_CLOUD_USE_WEBSOCKET | true | Stream via WebSocket. Set false to disable |
BUNQUEUE_CLOUD_USE_HTTP | true | Upload via HTTP. Set false to disable |
BUNQUEUE_CLOUD_REMOTE_COMMANDS | true | Allow remote commands from the dashboard. Set false to disable |
Client & CLI
Section titled “Client & CLI”| Variable | Type | Default | Description |
|---|---|---|---|
BUNQUEUE_MODE | string | embedded | Connection mode for the MCP server (embedded or tcp) |
BUNQUEUE_HOST | string | localhost | Server host for the MCP server in TCP mode; also a CLI fallback for --host |
BUNQUEUE_PORT | number | 6789 | Server port for the MCP server in TCP mode |
BUNQUEUE_POOL_SIZE | number | 2 | Connection pool size for the MCP server in TCP mode |
BUNQUEUE_EMBEDDED | string | (none) | Set to 1 to force embedded mode for the client library |
NO_COLOR | string | (none) | Set to 1 to disable colored CLI output |
# Point the MCP server at a remote bunqueue instanceBUNQUEUE_MODE=tcp BUNQUEUE_HOST=your-server.com BUNQUEUE_PORT=7000 bunx --package=bunqueue bunqueue-mcpThe MCP server also reads BUNQUEUE_TOKEN for authentication.
CLI port fallback. When --port is not passed, the CLI reads, in priority order: TCP_PORT > BUNQUEUE_TCP_PORT > BQ_TCP_PORT. Using TCP_PORT means the same variable that binds the server also routes the client in the same shell:
export TCP_PORT=7000bunqueue stats # connects to localhost:7000CLI host fallback. When --host is not passed: HOST > BUNQUEUE_HOST > BQ_HOST.
Complete examples
Section titled “Complete examples”Development
Section titled “Development”TCP_PORT=6789HTTP_PORT=6790BUNQUEUE_DATA_PATH=./data/dev.dbLOG_LEVEL=debugLOG_FORMAT=textProduction
Section titled “Production”TCP_PORT=6789HTTP_PORT=6790BUNQUEUE_DATA_PATH=/var/lib/production.dbLOG_LEVEL=infoLOG_FORMAT=jsonAUTH_TOKENS=prod-token-abc123,prod-token-xyz789
# S3 BackupS3_BACKUP_ENABLED=1S3_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLES3_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEYS3_BUCKET=company-bunqueue-backupsS3_REGION=us-east-1S3_BACKUP_INTERVAL=3600000S3_BACKUP_RETENTION=30S3_BACKUP_PREFIX=production/Docker Compose
Section titled “Docker Compose”services: bunqueue: image: bunqueue:latest ports: - '6789:6789' - '6790:6790' volumes: - bunqueue-data:/data environment: - BUNQUEUE_DATA_PATH=/data/queue.db - LOG_FORMAT=json - AUTH_TOKENS=${AUTH_TOKENS} - S3_BACKUP_ENABLED=1 - S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID} - S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY} - S3_BUCKET=${S3_BUCKET} - S3_REGION=${S3_REGION}
volumes: bunqueue-data:Kubernetes manifests and more deployment recipes are in the deployment guide.
Precedence
Section titled “Precedence”When the same setting comes from several sources:
- Command-line arguments (highest)
- Configuration file
- Environment variables
- Default values (lowest)
# Command-line winsTCP_PORT=6789 bunqueue start --tcp-port 7000# Uses port 7000