Configuration
Every SEQ_* variable, the queue backends and the roles.
apps/server/src/config/env.ts by pnpm generate. Do not edit it by hand; change the source and regenerate.Everything is configured through environment variables, Svix-style: you choose the database and the queue, and one image runs every role.
Variables
| Variable | Type | Required | Default | Meaning |
|---|---|---|---|---|
SEQ_DB_DSN | string | yes | Postgres connection string. Only Postgres is supported. A transaction pooler is fine: no session-level features are used. | |
SEQ_QUEUE | postgres, redis, memory | no | "postgres" | The queue backend. postgres needs nothing else and is a transactional outbox; redis needs SEQ_REDIS_DSN; memory is for development and tests only. |
SEQ_REDIS_DSN | string | with SEQ_QUEUE=redis | Redis connection, required when SEQ_QUEUE=redis. Enable persistence on the Redis side. | |
SEQ_ENCRYPTION_KEYS | string | yes | Encryption keys for every stored secret, id:base64key[,id:base64key...]; the first entry encrypts, every entry decrypts. Generate one with oseq secrets new-key. Back it up with the database: without it the stored secrets are unreadable and must be re-entered. | |
SEQ_ADMIN_TOKEN | string | for api and all | The operator token that creates projects and keys (/v1/admin/*). Required by the api and all roles. Long and random. | |
SEQ_PUBLIC_URL | URL | no | "http://localhost:8080" | The base URL providers call back: inbound webhooks, the Google OAuth return and the opt-out links. The OpenAPI document served by the instance lists it as its server. |
SEQ_PORT | number | no | 8080 | HTTP port. The API for api and all; /healthz and /readyz only for worker. |
SEQ_HOST | string | no | "0.0.0.0" | The interface to bind. |
SEQ_ROLES | api, worker, all | no | "all" | api serves HTTP, worker runs the scheduler and the queue consumers, all does both in one process. |
SEQ_RUN_MIGRATIONS | flag: 1 or true | no | Apply the seq and auth migrations at boot, serialized by a row lock so replicas starting together do not race. | |
SEQ_CONCURRENCY | number | no | 8 | Messages in flight per queue per replica. |
SEQ_DISABLED_CHANNELS | comma-separated list | no | Platform-wide kill switch per channel, comma-separated (sms,linkedin). Steps on a disabled channel are deferred, not skipped. | |
SEQ_PAUSED | flag: 1 or true | no | Platform-wide stop: the planner claims nothing while it is on. In-flight steps finish. | |
SEQ_DEV_MOCK_PROVIDERS | flag: 1 or true | no | Every project uses the mock adapters: nothing reaches Google, Allo or Attio, sends land in the timeline, and POST /hooks/mock/\{slug\} simulates replies, bounces, bookings and calls. Refused when NODE_ENV=production. | |
SEQ_LOG_LEVEL | fatal, error, warn, info, debug, trace | no | "info" | Pino log level. |
SEQ_METRICS | flag: 1 or true | no | Reserved for a Prometheus /metrics endpoint. Accepted by the schema; the endpoint is not served yet. | |
SEQ_DB_POOL | number | no | 10 | Postgres connections per process. |
NODE_ENV | string | no | "development" | production turns off pretty logs and refuses SEQ_DEV_MOCK_PROVIDERS. |
Three rules are checked after parsing: SEQ_QUEUE=redis needs SEQ_REDIS_DSN; the api and all roles need SEQ_ADMIN_TOKEN; SEQ_DEV_MOCK_PROVIDERS is refused when NODE_ENV=production.
Queue backends
The queue interface is send, read with a visibility timeout, release, delete and archive; everything above it is identical across backends.
SEQ_QUEUE | Extra infrastructure | Notes |
|---|---|---|
postgres | none | the default; the table seq.queue_messages with FOR UPDATE SKIP LOCKED; an enqueue joins the transaction that records the work (a transactional outbox) |
redis | Redis 7+ | higher throughput for large installs; an enqueue cannot join the database transaction, so the reaper's sweep re-enqueues anything recorded but never queued |
memory | none | development and tests only; the planner and the reaper rebuild work from the tables on boot |
Because the database is the truth and queue messages are hints, a lost or empty queue never loses work. See Queues.
Roles
SEQ_ROLES | Runs | Exposed publicly |
|---|---|---|
api | the public API, inbound provider webhooks, the OAuth return, the opt-out page, /healthz and /readyz | yes |
worker | the scheduler (planner, signals, poll, reaper, retention, webhooks) and the queue consumers (email, SMS, signals, deliveries) | no; it listens for /healthz and /readyz only |
all | both in one process | yes |
A worker process still registers the API routes on its port; do not expose that port. Readiness for a worker also checks that the scheduler ran a job in the last two minutes.
Kill switches
SEQ_PAUSED=1 stops the planner platform-wide; SEQ_DISABLED_CHANNELS=sms defers every step of a channel. Both are read on every tick, so they take effect without a restart. Per-project switches exist too: PUT /v1/engine/flags/global and PUT /v1/engine/flags/channel:sms with { "value": false }.