- Docs
- Run in Production
- Configuration File
Server configuration in one typed file.
Configure the whole bunqueue server from a single typed bunqueue.config.ts instead of scattered environment variables. Every option has IntelliSense, every section is optional.
This page is about configuring the standalone server (Server Mode). Embedded mode needs no config file, it takes options directly in the Queue/Worker constructors.
Quick start
Section titled “Quick start”Create a bunqueue.config.ts in your project root:
import { defineConfig } from 'bunqueue';
export default defineConfig({ server: { tcpPort: 6789, httpPort: 6790, }, storage: { dataPath: './data/queue.db', },});Then start normally:
bunqueue startThe config file is auto-discovered, no flags needed. defineConfig() gives you full TypeScript IntelliSense, so you never have to guess an option name.
Priority order
Section titled “Priority order”When the same option is set in more than one place, the first of these wins:
- CLI flags,
bunqueue start --tcp-port 8000 - Config file,
bunqueue.config.ts - Environment variables,
TCP_PORT=8000 - Built-in defaults
Use the config file as your baseline and override per environment with env vars or flags.
Picking a config file
Section titled “Picking a config file”bunqueue looks in your project root for bunqueue.config.ts, then bunqueue.config.js, then bunqueue.config.mjs. To use a specific file:
bunqueue start --config ./config/production.config.ts# Short formbunqueue start -c ./config/staging.config.tsValidation
Section titled “Validation”The server checks the whole file when it starts, before it binds a port:
- A value the server cannot use stops startup with an error that names the key,
for example
timeouts.stats must be a finite number of milliseconds >= 1 (got 0)orauth.tokens must be an array of strings (got "secret"). Every problem is reported at once, together with invalid environment variables and CLI flags. - Numbers must be finite; a fractional value is rounded down to a whole number.
Ports,
timeouts.shutdown,timeouts.statsand the backupinterval/retentionalso accept a numeric string, sotcpPort: process.env.PORTworks. - Boolean keys take
trueorfalse. Any other value is read as earlier releases read it, by JavaScript truthiness, and logged as a warning: a non-empty string is true ('false'and'0'included) and''is false. Withenabled: process.env.S3_BACKUP_ENABLED, convert the variable to a boolean (process.env.S3_BACKUP_ENABLED === 'true'). nullmeans “not set” for any key or section (bucket: process.env.S3_BUCKET ?? null).- Auth tokens must be non-empty strings: an empty or whitespace-only entry in
auth.tokensstops startup,auth.tokens[0] must not be empty or whitespace-only (got ""), and so does a missing one,auth.tokens[0] must be a non-empty string (got undefined). Tokens are trimmed. - Values that earlier releases replaced with a default keep that default and are
logged as a warning, for example a negative
telemetry.maxPrometheusQueues(100) or an invalidstorage.completedRetentionMs(retention off). - An unknown key (a typo such as
completedRetentionMS, or a key from a newer version) does not stop the server: it is logged as a warning,Unknown config key "storage.completedRetentionMS" is ignored, and the setting keeps its default.defineConfig()already flags such keys in your editor.
defineConfig() itself stays a plain pass-through: the checks run when the
server loads the file.
Full configuration reference
Section titled “Full configuration reference”Every section is optional. Only specify what you need.
server
Section titled “server”TCP and HTTP server settings.
defineConfig({ server: { tcpPort: 6789, // TCP server port (default: 6789) httpPort: 6790, // HTTP/REST API port (default: 6790) host: '0.0.0.0', // Bind address (default: 0.0.0.0) tcpSocketPath: undefined, // Reserved, not applied yet: TCP always binds host:port httpSocketPath: undefined, // Unix socket for HTTP (overrides host/port) tlsCertFile: undefined, // PEM certificate, enables native TLS on TCP + HTTP (with tlsKeyFile) tlsKeyFile: undefined, // PEM private key (set both or neither, partial config is a startup error) },});Authentication tokens for clients. Set this on any server reachable from a network.
defineConfig({ auth: { tokens: ['my-secret-token'], // Auth tokens for TCP/HTTP requireAuthForMetrics: false, // Require auth for /prometheus (env: METRICS_AUTH) },});Every token must contain at least one non-whitespace character. An empty or
whitespace-only token stops startup with an error naming the entry, because it would
match a request that carries no credentials. Watch for a fallback such as
tokens: [process.env.API_TOKEN ?? '']: it type-checks, and it yields [''] when the
variable is unset, so the server refuses to start. tokens: [] is accepted and
disables authentication, and auth.tokens takes precedence over AUTH_TOKENS.
Tokens are trimmed on both sides of the comparison: a client that sends the same
secret with a trailing newline still authenticates.
storage
Section titled “storage”Where jobs persist. Memory and SQLite remain the defaults; PostgreSQL is an optional standalone-server backend for multiple active brokers.
defineConfig({ storage: { driver: 'sqlite', // 'memory' | 'sqlite' | 'postgres' dataPath: './data/queue.db', // required for explicit SQLite maxCompletedJobs: 50_000, // completed-job hot cache/recovery window completedRetentionMs: 7 * 24 * 60 * 60 * 1000, // optional durable retention },});maxCompletedJobs bounds the in-memory completed-job projection (a whole
number ≥ 1); it does not delete SQLite rows. Set completedRetentionMs to opt
into age-based durable cleanup (up to 1,000 oldest eligible rows per 10-second
cleanup tick). The default is null, so completed rows remain until
queue.clean(...), obliterate, or another explicit policy removes them.
Results still needed by live dependency consumers are protected until the
consumer leaves the graph. Finite non-negative values are rounded down to whole
milliseconds and null disables retention. A negative, non-finite or
non-numeric value also disables retention, as in earlier releases, and the server
logs a warning naming the key.
The server CLI equivalents are --max-completed-jobs and
--completed-retention-ms; environment equivalents are documented in the
environment reference.
Without driver, a PostgreSQL URL selects PostgreSQL, a data path selects
SQLite, and neither selects in-memory storage. PostgreSQL configuration:
defineConfig({ storage: { driver: 'postgres', url: process.env.BUNQUEUE_POSTGRES_URL!, namespace: 'production', // isolates installations sharing one database brokerId: process.env.HOSTNAME, // unique per active broker; auto-generated if omitted poolSize: 4, // default 4, runtime minimum 2 leaseDurationMs: 30_000, // default 30s, runtime minimum 1s pollIntervalMs: 250, // durable event/cron fallback, minimum 25ms statementTimeoutMs: 30_000, lockTimeoutMs: 5_000, idleTransactionTimeoutMs: 30_000, maxConcurrentOperations: 16, maxQueuedOperations: 128, maxSnapshotJobs: 100_000, maxSnapshotPayloadBytes: 256 * 1024 * 1024, },});Do not combine url with dataPath. PostgreSQL support is server-only and is
validated against PostgreSQL 15, 16, 17, and 18.6; embedded queues continue to
use memory/SQLite. MySQL is not supported. See
Storage backends.
telemetry
Section titled “telemetry”Bound labelled Prometheus output independently from the exact global totals:
defineConfig({ telemetry: { maxPrometheusQueues: 100, // 0 disables per-queue label series },});The environment equivalent is METRICS_MAX_QUEUES. The default is 100; an
invalid or negative value keeps 100 and logs a warning.
Allowed origins for browser access to the HTTP API.
defineConfig({ cors: { origins: ['https://myapp.com', 'https://admin.myapp.com'], },});origins also accepts a comma-separated string, like CORS_ALLOW_ORIGIN
('*', 'https://a.example,https://b.example'). An undefined, null or empty
entry ([process.env.FRONTEND_URL!] with the variable unset) is dropped with a
warning.
backup
Section titled “backup”Automatic snapshots of the SQLite database to any S3-compatible storage (AWS, MinIO, Cloudflare R2). See S3 Backup.
defineConfig({ backup: { enabled: true, bucket: 'my-bunqueue-backups', accessKeyId: process.env.S3_ACCESS_KEY_ID, secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, sessionToken: process.env.S3_SESSION_TOKEN, // Temporary credentials region: 'eu-west-1', // Default: us-east-1 endpoint: undefined, // Custom S3 endpoint (MinIO, R2, etc.) virtualHostedStyle: undefined, // Force bucket-in-host addressing interval: 6 * 60 * 60 * 1000, // Backup interval in ms (default: 6h, minimum 60000) retention: 7, // Backups to keep (default: 7, minimum 1) prefix: 'backups/', // S3 key prefix (default: 'backups/') },});The server also needs storage.dataPath (or a data-path environment variable);
automatic backup is unavailable in in-memory and PostgreSQL modes. A backup that
cannot run (no bucket or credentials, an interval under a minute, an invalid
retention) does not stop the server: it logs S3 backup configuration invalid with
the settings to fix and runs without backups. An invalid value is never used.
timeouts
Section titled “timeouts”defineConfig({ timeouts: { shutdown: 30000, // Graceful shutdown timeout in ms (default: 30000, 0 = do not wait) stats: 300000, // Stats logging interval in ms (default: 300000, minimum 1) },});The environment equivalents are SHUTDOWN_TIMEOUT_MS and STATS_INTERVAL_MS; the
config file wins.
timeouts.worker and timeouts.lock are accepted but ignored: they never took
effect, and the server logs a warning when they are present. Set the worker
heartbeat freshness window with WORKER_TIMEOUT_MS (default 30000; a worker whose
last heartbeat is older is shown as stale and is removed after three times that
window) and the internal lock acquisition timeout with LOCK_TIMEOUT_MS (default
5000), both in milliseconds.
webhooks
Section titled “webhooks”webhooks.maxRetries and webhooks.retryDelay are accepted but ignored: they
never took effect, and the server logs a warning when they are present. Configure
webhook delivery retries with WEBHOOK_MAX_RETRIES (delivery
attempts per event, first try included, default 3, minimum 1) and
WEBHOOK_RETRY_DELAY_MS (base delay in ms; attempt n + 1 waits n × the delay,
default 1000).
logging
Section titled “logging”defineConfig({ logging: { level: 'info', // 'debug' | 'info' | 'warn' | 'error' format: 'json', // 'text' | 'json' },});Values are matched in any case, like the LOG_LEVEL and LOG_FORMAT
environment variables they override, and the level also accepts warning, trace,
verbose, fatal and critical. Any other value is logged as a warning and
ignored. With the Docker image, LOG_FORMAT=json keeps JSON output even when the
file says text.
Complete examples
Section titled “Complete examples”Development
Section titled “Development”import { defineConfig } from 'bunqueue';
export default defineConfig({ storage: { dataPath: './data/dev.db' }, logging: { level: 'debug' },});Production
Section titled “Production”import { defineConfig } from 'bunqueue';
export default defineConfig({ server: { tcpPort: 6789, httpPort: 6790, host: '0.0.0.0' }, auth: { tokens: [process.env.BUNQUEUE_AUTH_TOKEN!], requireAuthForMetrics: true, }, storage: { dataPath: '/data/bunqueue/queue.db' }, telemetry: { maxPrometheusQueues: 100 }, cors: { origins: [process.env.FRONTEND_URL!] }, backup: { enabled: true, bucket: process.env.S3_BUCKET!, accessKeyId: process.env.S3_ACCESS_KEY_ID, secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, region: 'eu-west-1', interval: 3600000, // Every hour retention: 30, }, logging: { level: 'info', format: 'json' }, timeouts: { shutdown: 60000 },});Docker / Kubernetes
Section titled “Docker / Kubernetes”Mix the config file (static settings baked into the image) with environment variables (per-deployment values). Remember: when both define the same option, the config file wins.
// bunqueue.config.ts, static settings in the imageimport { defineConfig } from 'bunqueue';
export default defineConfig({ server: { host: '0.0.0.0' }, logging: { format: 'json' }, backup: { enabled: true, region: 'eu-west-1' },});# Dynamic settings fill what the config file leaves unsetdocker run \ -e TCP_PORT=6789 \ -e S3_BUCKET=my-bucket \ -e S3_ACCESS_KEY_ID=xxx \ -e S3_SECRET_ACCESS_KEY=xxx \ my-bunqueue-imageImporting defineConfig
Section titled “Importing defineConfig”Available from both package exports:
import { defineConfig } from 'bunqueue';// orimport { defineConfig } from 'bunqueue/client';bunqueue Cloud
Section titled “bunqueue Cloud”defineConfig({ cloud: { url: 'https://cloud.bunqueue.io', apiKey: process.env.BUNQUEUE_CLOUD_API_KEY, instanceId: process.env.BUNQUEUE_CLOUD_INSTANCE_ID, },});