n8n Queue Mode Tested: 2.4x Throughput vs Regular Mode
Tested by M. Aziz, backend engineer at Selfhost.dev · n8n 2.40.7, Postgres 17.10 and Redis 7.4.6 on a Selfhost.dev server in Falkenstein, Germany, November 2026 ·
Our 4 vCPU server was failing n8n requests by the thousand, and three of its cores had nothing to do. In regular mode, n8n pushed every Code node through a single task runner pinned to one core, while main’s memory climbed to 6.9 GB. n8n queue mode hands each execution to worker processes through Redis.
With 2 workers, the same server answered 519 executions a minute at 50 requests a second with zero errors, 2.4 times regular mode on that Code-heavy test. With 4 workers, the errors came back.
That’s the part most guides skip: queue mode isn’t “more workers, more speed”. Below one busy core it only adds RAM, and one setting in regular mode may be all you need. Below are the numbers to decide, the tested Compose file and six failure drills, all on n8n 2.40.7.
Table of Contents
KEY FACTS
- Throughput: on one 4 vCPU / 8 GB server, n8n 2.40.7 queue mode with 2 workers answered 519 Code-heavy executions a minute at 50 requests/s, zero errors; regular mode answered 215.
- Low load: at 5 requests/s both modes answered about 295 a minute at the same 0.9 s median; queue mode added 227 to 901 MB of idle RAM.
- Workers: on 4 vCPUs, 2 workers beat 1 (regular mode’s ceiling) and 4 (1,013 errors at 50 requests/s).
- Concurrency: keep the default of 10; at 5, two workers fell to 426 a minute with 238 errors.
- Binary data: no S3 needed; in queue mode n8n stores binary data in Postgres by default.
- Redis: with AOF on, 20 of 20 waiting executions survived a Redis restart; without it, all 20 crashed.
On this page: What it is · vs regular mode · Benchmarks · Common advice vs measured · The cheaper fix · Worker concurrency · Compose file · SQLite to Postgres · Redis · Postgres connections · Failure drills · Monitoring · Field notes · Checklist · FAQ
What is n8n queue mode?
n8n queue mode is an execution mode in which the main instance hands executions to separate worker processes through a Redis queue, with Postgres as the shared database. You turn it on with EXECUTIONS_MODE=queue on every n8n process and start the workers with n8n worker.
What happens to one webhook call:
- Main receives it, writes the execution to Postgres and puts its ID on the Redis queue.
- A free worker takes the job, reads the workflow from Postgres and runs it, with Code nodes in its own task runner.
- The worker writes the result to Postgres; if the webhook waits for the last node, the reply returns to main through Redis.

The parts:
- Main instance: editor, API, triggers and webhooks; no production executions.
- Redis: the queue (n8n 2.40.7 uses the Bull 4 library, not BullMQ).
- Workers: run executions, up to
--concurrencyeach (default 10). - Postgres: shared by every process; SQLite is not supported.
- Task runners: in n8n 2.x, Code nodes run in a separate runner, so each worker comes as a pair: worker + runner.
We skipped the optional webhook processors (n8n webhook): they help across several machines, but on one server they compete for the same CPUs.
n8n queue mode vs regular mode
Regular mode runs everything in one n8n process with one task runner; queue mode splits the work across worker processes, each with its own runner. On our server that was the whole difference: the single runner used one CPU core of four.
| Regular mode | Queue mode | |
|---|---|---|
| What runs executions | The main n8n process | Worker processes (n8n worker) |
| Code nodes run in | One task runner (one core) | One task runner per worker |
| Max parallel runs | No limit by default (N8N_CONCURRENCY_PRODUCTION_LIMIT=-1) | Workers × --concurrency (default 10 each) |
| When a heavy workflow runs | Shares CPU with the editor and every webhook | Runs on a worker; main and the editor stay responsive |
| Where a backlog waits | In main’s memory (354 MB → 6.9 GB in our test) | In Redis (3.4 MB at most in our test) |
| Database | SQLite or Postgres | Postgres only |
| Extra services | None | Redis, workers, one runner per worker |
| Failure points | n8n, its database | Also Redis and each worker |
| Stack RAM at idle (measured) | 476 MB (main + runner + Postgres) | 703 MB (1 worker), 919 MB (2), 1,377 MB (4), Redis included |
At idle on n8n 2.40.7, queue mode with 2 workers used 919 MB for the whole stack, against 476 MB for regular mode on the same server. For the RAM one n8n instance needs before any of this, see how much RAM a single n8n instance needs.
Do you need n8n queue mode? Benchmarks with 1, 2 and 4 workers
Yes, once your Code-heavy load outgrows one CPU core; no, below that. At 5 requests a second every setup answered about 295 executions a minute. At 20 and 50, regular mode broke and queue mode with 2 workers held.
How we tested
| Item | What we used |
|---|---|
| Server | Selfhost.dev Projects server: 4 vCPU (shared, x86), 8 GB RAM (7.7 GB usable), Falkenstein, Germany |
| Versions | n8n 2.40.7, n8n runners 2.40.7, Postgres 17.10, Redis 7.4.6, all pinned |
| Test workflow | Webhook (respond when last node finishes) → Code node (fixed integer loop, 187 ms warm on this server) → Wait 0.5 s (a slow API call) → Set |
| Load generator | k6 v0.43.1 on a laptop in India, a separate machine; about 320 ms HTTP round trip to the server |
| Load | Constant arrival rate of 5, 20 and 50 requests/s for 3 minutes each, 120 s client timeout, at most 1,000 requests in flight |
| Per run | Fresh deploy, 10 warm-up requests, 20 s idle before and after the load |
| Measured | Answered executions per minute, p50/p95/p99 response time, errors by type, CPU and RAM per container (cgroup counters sampled every second), Redis memory and queue length, Postgres connections, editor responsiveness |
Editor responsiveness is the time to load one workflow over the editor’s own REST call (GET /rest/workflows/:id), every 5 s. Each cell is one run. We ran the set twice, on Postgres 16 and then 17 (shown); cells moved by up to 25%, so read smaller gaps as noise.
n8n performance at 5, 20 and 50 requests a second
All five setups ran on the same server with the same workflow, in 3-minute runs at a constant request rate. “Answered/min” counts requests that returned HTTP 200 within 120 s, per minute of load. Errors are HTTP 500/503 from n8n or client timeouts.
| Setup | 5 req/s: answered/min · p95 | 20 req/s: answered/min · errors · p95 | 50 req/s: answered/min · errors · p95 | Peak RAM, whole stack | Editor load p95 under load |
|---|---|---|---|---|---|
| Regular, defaults | 297 · 2.6 s | 268 · 1,045 · 90 s | 215 · 3,851 · 100 s | 7.1 GB | 21 to 41 s |
Regular, N8N_CONCURRENCY_PRODUCTION_LIMIT=10 | 295 · 2.3 s | 331 · 1 · 114 s | 112 · 749 · 120 s | 0.9 GB | 0.42 s |
| Queue, 1 worker | 295 · 2.7 s | 314 · 51 · 119 s | 114 · 750 · 120 s | 1.2 GB | 0.40 s |
| Queue, 2 workers | 295 · 1.0 s | 513 · 0 · 81 s | 519 · 0 · 111 s | 1.8 GB | 0.55 s |
| Queue, 4 workers | 295 · 1.0 s | 557 · 0 · 74 s | 505 · 1,013 · 93 s | 2.8 GB | 1.3 to 8.7 s |
On a 4 vCPU / 8 GB server, n8n 2.40.7 in regular mode answered 268 executions a minute at 20 requests/s with 1,045 errors; queue mode with 2 workers answered 513 a minute with none.
At 50 requests/s, queue mode with 2 workers answered 519 executions a minute with zero errors, 2.4 times regular mode’s 215.

What happened in each setup:
- Regular, defaults: the one task runner sat at 100% of one core while three more were free. Main held every waiting request in memory, growing from 354 MB to 6.9 GB. At 20 requests/s the 1,045 errors included 726 HTTP 500s and 285 HTTP 503s, and the editor took 21 s to load a workflow.
- Queue, 1 worker: the same single-core ceiling, but the backlog waited in Redis. 51 requests passed the 120 s client timeout at 20 requests/s.
- Queue, 2 workers: two runners, two cores, zero errors. Main stayed at 440 to 590 MB.
- Queue, 4 workers: fastest at 20 requests/s (557 a minute), but at 50 no faster than 2 and with 1,013 errors: 714
503 {"code":503,"message":"Database is not ready!"}, 175 HTTP 500s, 124 timeouts. A pool size of 10 removed them in this run but not on Postgres 16 (930); our guess is CPU contention (not proven).
Long p95 values show the backlog, not one execution’s speed, so compare answered/min.
Our numbers sit far below n8n’s documented 220 executions a second on one instance, which used a two-node Webhook and Edit Fields workflow. Ours spends 187 ms of CPU in a Code node and waits 0.5 s on every run. The shape matches, though: in n8n’s scalability benchmark, a 16 vCPU machine reached 16.2 requests a second in single mode and 162 in queue mode.
What these numbers don’t cover:
- One Code-heavy workflow on one shared 4 vCPU server. Workflows that mostly wait on APIs, query databases or move large files may scale differently.
- One run per cell, with up to 25% variation between repeat runs.
- Response times include about 320 ms of network between our load generator and the server.
- n8n 2.40.7. Later versions changed how workers claim jobs and shut down, so re-check the failure drills on yours.
Treat 2 workers per 4 vCPU as a starting point, then measure your own workflows.
Common advice vs what we measured
Five common pieces of queue mode advice didn’t hold on our server.
| Common advice | What we measured (n8n 2.40.7, one 4 vCPU / 8 GB server) |
|---|---|
| “Queue mode on one server adds no computing power” | For Code-heavy work it does: regular mode ran every Code node in one runner on one core. 2 workers answered 519 executions a minute at 50 requests/s, 2.4 times regular mode’s 215 |
| “Set worker concurrency to 5” | With 2 workers, 5/5 fell to 426 a minute with 238 errors at 50 requests/s; the default of 10 held 519 with none |
| “Start with one worker” | One worker kept the single-runner ceiling: 51 requests timed out at 20 requests/s, against 0 with 2 workers |
| “More workers, more throughput” | 4 workers answered no more than 2 at 50 requests/s (505 against 519 a minute) and added 1,013 errors |
| “Queue mode needs S3 for binary data” | n8n’s docs: “In queue mode, n8n uses database by default.” Our worker read a 300 kB upload from Postgres. S3 needs a Business or Enterprise licence |
If your server has 4 vCPUs and Code-heavy workflows, start with 2 workers at the default concurrency of 10, not 1 worker at 5.
The cheaper fix: a concurrency limit in regular mode
If a few heavy workflows spike at once, try N8N_CONCURRENCY_PRODUCTION_LIMIT in regular mode before queue mode. A limit of 10 kept main at 674 MB instead of 6.9 GB, held the editor at 0.42 s, and cut errors at 20 requests/s from 1,045 to 1.
The cost is waiting: extra executions queue inside main, first in, first out, and the median caller waited 62 s. It adds no capacity either; at 50 requests/s it answered 112 a minute. Per n8n’s concurrency docs, it counts only webhook and trigger runs, not manual or sub-workflow ones.
n8n worker concurrency: is the default of 10 right?
Yes, on our server. We varied --concurrency together with the runner’s own limit (N8N_RUNNERS_MAX_CONCURRENCY, 5 in the n8n one-click template we started from). 2 workers, each run once:
| Worker concurrency / runner limit | 20 req/s: answered/min · p95 | 50 req/s: answered/min · errors |
|---|---|---|
| 5 / 5 | 502 · 82 s | 426 · 238 |
| 10 / 5 (default concurrency, template runner limit) | 513 · 81 s | 519 · 0 |
| 10 / 10 | 491 · 84 s | 517 · 0 |
| 20 / 20 | 499 · 83 s | 514 · 0 |
With 2 workers on 4 vCPUs, 10/5, 10/10 and 20/20 answered 491 to 519 executions a minute, within noise of each other. Only 5/5 fell behind at 50 requests/s (426 a minute, 238 errors). An 18% gain for 10/10 in our Postgres 16 run did not repeat.
CPU was the ceiling: the stack used 3.2 to 3.5 of 4 cores in every 2-worker run at 50 requests/s, so more parallel tasks only waited for the same cores.
One setting overrides the flag. In queue mode, each worker takes its limit from N8N_CONCURRENCY_PRODUCTION_LIMIT when it’s set to anything but -1; it’s per worker, not a total. So a value left over from regular mode quietly changes how many executions each worker takes, whatever --concurrency says. n8n Cloud’s concurrency limits per plan are a separate cap.
When to turn on queue mode: our engineer’s call
Mohammad Aziz, backend engineer at Selfhost.dev, who ran these tests: “If your server runs a few hundred light executions an hour, I’d leave queue mode off. It adds Redis, more containers and 0.2 to 0.9 GB of RAM, and nothing gets faster at that load: at 5 requests/s every setup I tested answered with the same 0.9 s median. I’d turn it on when I see one of two things: the runner container pinned at 100% of one core while the other cores sit idle, or the editor stalling whenever workflows run. On a 4 vCPU server I’d start with 2 workers and leave
--concurrencyat its default of 10: going lower hurt, going higher didn’t help. I’d stop adding workers once the CPU is full. At 50 requests/s, 2 workers already used 3.5 of 4 cores, and 4 workers added errors, not throughput.”
Every number above came from one 4 vCPU / 8 GB server, with main, 2 workers, Redis and Postgres all on it.
See what that exact server costs per hour, no signup
Set up n8n queue mode with Docker Compose
This is the stack behind every queue mode number above: main, workers, a task runner per n8n process, Redis and Postgres, every version pinned. With 2 workers it runs 8 containers, and it went healthy as one Docker Compose service on a Selfhost.dev Projects server.
Before you copy it: the example serves n8n over plain HTTP on port 5678 with secure cookies off, which is fine for a first test only. For production, put n8n behind HTTPS with a real domain and delete the N8N_SECURE_COOKIE line.
Set five values first, in a .env file or your platform’s variables:
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32) # same for every n8n process, never change it
POSTGRES_PASSWORD=$(openssl rand -hex 24)
REDIS_PASSWORD=$(openssl rand -hex 24)
RUNNERS_AUTH_TOKEN=$(openssl rand -hex 24)
N8N_PUBLIC_URL=http://<your-server-ip>:5678/
services:
n8n-postgres:
image: postgres:17.10-alpine
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: n8n
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
interval: 5s
timeout: 5s
retries: 10
n8n-redis:
image: redis:7.4.6-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes --appendfsync everysec --maxmemory-policy noeviction
environment:
REDISCLI_AUTH: "${REDIS_PASSWORD}"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 5s
timeout: 5s
retries: 10
n8n-main:
image: n8nio/n8n:2.40.7
restart: unless-stopped
environment: &n8n-env
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: n8n-redis
QUEUE_BULL_REDIS_PORT: "6379"
QUEUE_BULL_REDIS_PASSWORD: "${REDIS_PASSWORD}"
QUEUE_HEALTH_CHECK_ACTIVE: "true"
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: n8n-postgres
DB_POSTGRESDB_PORT: "5432"
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: "${POSTGRES_PASSWORD}"
N8N_ENCRYPTION_KEY: "${N8N_ENCRYPTION_KEY}"
N8N_RUNNERS_MODE: external
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
N8N_RUNNERS_BROKER_PORT: "5679"
N8N_RUNNERS_AUTH_TOKEN: "${RUNNERS_AUTH_TOKEN}"
N8N_EDITOR_BASE_URL: "${N8N_PUBLIC_URL}"
N8N_WEBHOOK_URL: "${N8N_PUBLIC_URL}"
N8N_SECURE_COOKIE: "false" # plain HTTP on the bare port; remove behind HTTPS
EXECUTIONS_DATA_PRUNE: "true"
EXECUTIONS_DATA_MAX_AGE: "168"
GENERIC_TIMEZONE: UTC
TZ: UTC
N8N_DIAGNOSTICS_ENABLED: "false"
ports:
- "5678:5678"
volumes:
- n8n-main-data:/home/node/.n8n
depends_on:
n8n-postgres: { condition: service_healthy }
n8n-redis: { condition: service_healthy }
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/healthz/readiness"]
interval: 10s
timeout: 10s
retries: 30
runner-main:
image: n8nio/runners:2.40.7
restart: unless-stopped
environment:
N8N_RUNNERS_AUTH_TOKEN: "${RUNNERS_AUTH_TOKEN}"
N8N_RUNNERS_MAX_CONCURRENCY: "5"
N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT: "15"
N8N_RUNNERS_TASK_BROKER_URI: http://n8n-main:5679
depends_on: [n8n-main]
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5680/healthz"]
interval: 10s
timeout: 10s
retries: 10
n8n-worker-1:
image: n8nio/n8n:2.40.7
restart: unless-stopped
command: worker --concurrency=10
environment: *n8n-env
depends_on:
n8n-main: { condition: service_healthy }
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/healthz"]
interval: 10s
timeout: 10s
retries: 10
stop_grace_period: 60s
runner-worker-1:
image: n8nio/runners:2.40.7
restart: unless-stopped
environment:
N8N_RUNNERS_AUTH_TOKEN: "${RUNNERS_AUTH_TOKEN}"
N8N_RUNNERS_MAX_CONCURRENCY: "5"
N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT: "15"
N8N_RUNNERS_TASK_BROKER_URI: http://n8n-worker-1:5679
depends_on: [n8n-worker-1]
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5680/healthz"]
interval: 10s
timeout: 10s
retries: 10
# n8n-worker-2 and runner-worker-2: copy the two blocks above, replace -1 with -2
volumes:
postgres-data:
redis-data:
n8n-main-data:
To keep it short, this version shares settings through a YAML anchor and writes out one worker. Exactly as shown, it ran locally with all 6 containers healthy; the full 2-worker file is the one that ran on Selfhost.dev. Any server with Docker Compose can run it, though n8n hosts compared on what breaks n8n differ on everything around it.
Why it looks like this:
- Workers are separate services, not
deploy.replicas: Selfhost.dev’s Compose route doesn’t acceptdeploy:, and each worker needs its own runner. - Postgres and Redis are named
n8n-postgresandn8n-redis. On a Coolify-based host (Selfhost.dev included),postgresandredisalready point at the platform’s own services (field note 1). - Every runner has a healthcheck, or the platform marks the service failed after 10 minutes (field note 2).
What changes if you run it on Selfhost.dev’s Compose route:
| Selfhost.dev | You | |
|---|---|---|
| The server | Provisioned and set up for you | Pick the size |
| Deploying the stack | From your repo’s Compose file, redeployed on every push | Keep the file in a repo |
| Domain and HTTPS | Custom domain with TLS issued and renewed | Point your domain |
| Logs and metrics | Live, per service | Read them |
| n8n, Redis and Postgres settings | Set in your Compose file and variables | |
| Your workflows | Build and run them |
This stack went healthy on that route: 8 containers on one 4 vCPU / 8 GB server, with the domain and TLS handled for you.
Run this queue mode stack on a server we set up
File already in a repo? Deploy it with the $5 welcome credit, no card
n8n queue mode environment variables and task runners
Every n8n process needs the same queue, database and key settings; each runner needs only its token and its own process’s address.
| Variable | Value we used | Needed on | What breaks without it |
|---|---|---|---|
EXECUTIONS_MODE | queue | main, workers | Main runs everything itself; workers have nothing to do |
QUEUE_BULL_REDIS_HOST / _PORT / _PASSWORD | n8n-redis / 6379 / secret | main, workers | Default host is localhost: nothing connects. A wrong password logs WRONGPASS invalid username-password pair |
DB_TYPE | postgresdb | main, workers | Default is sqlite. A wrong value such as postgres is ignored and n8n silently starts on SQLite |
DB_POSTGRESDB_HOST / _DATABASE / _USER / _PASSWORD | n8n-postgres / n8n / n8n / secret | main, workers | No shared database |
N8N_ENCRYPTION_KEY | 64 hex characters | main, workers | Each process makes its own key; a worker with a different key refuses to start (failure drills) |
QUEUE_HEALTH_CHECK_ACTIVE | true | workers | No /healthz on workers, so no healthcheck (default false) |
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS | true | main | Runs from the editor’s Execute button run on main (default false) |
N8N_RUNNERS_MODE + broker settings | external, 0.0.0.0:5679 | main, workers | The runner container cannot connect |
N8N_RUNNERS_AUTH_TOKEN | secret | every n8n process and runner | Runners are refused |
N8N_RUNNERS_TASK_BROKER_URI | http://<its own n8n service>:5679 | each runner | A runner pointed at main serves only main; workers’ Code nodes wait |
N8N_EDITOR_BASE_URL, N8N_WEBHOOK_URL | the public URL | main | Webhook URLs shown in the editor use localhost |
Start order: main before workers
Main starts first, after Postgres and Redis report healthy; workers start after main is healthy. Main runs the database migrations on first start.
We also started a worker first, on an empty database. In n8n 2.40.7 it logged Acquiring database migration lock..., ran the migrations itself and reported n8n worker is now ready. Keep the depends_on order anyway, so one process migrates.
Check that a worker picked up the execution
A worker that is ready logs:
n8n worker is now ready
* Version: 2.40.7
* Concurrency: 10
* Pool: (default)
* Queue: jobs
Registered runner "launcher-javascript" (f018d708cb798768)
Registered runner "launcher-python" (34a3bca497971c72)
The two Registered runner lines show the worker’s own runner connected. Trigger a workflow; main logs Execution 5642 (job 5641) finished and a worker logs Worker started execution 1 (job 1) and Worker finished execution 1 (job 1). Each worker also answers GET http://<worker>:5678/healthz inside the Docker network.
Coming from SQLite? Move n8n to Postgres first
Queue mode needs Postgres. In our local test, n8n 2.40.7’s export:entities and import:entities moved a whole SQLite instance: owner login, active workflows, credentials and execution history.
# 1. Stop n8n, then export from the SQLite volume (same key as the running instance)
docker run --rm -v n8n_data:/home/node/.n8n -v "$PWD/exports":/exports \
-e N8N_ENCRYPTION_KEY="$KEY" --entrypoint n8n n8nio/n8n:2.40.7 \
export:entities --outputDir=/exports --includeExecutionHistoryDataTables=true
# 2. Start n8n once on Postgres (DB_TYPE=postgresdb, same N8N_ENCRYPTION_KEY) so it creates the schema, stop it, then:
docker run --rm --network <net> -v "$PWD/exports":/exports -v n8n_pg_data:/home/node/.n8n \
-e DB_TYPE=postgresdb -e DB_POSTGRESDB_HOST=n8n-postgres -e DB_POSTGRESDB_DATABASE=n8n \
-e DB_POSTGRESDB_USER=n8n -e DB_POSTGRESDB_PASSWORD="$PGPASS" -e N8N_ENCRYPTION_KEY="$KEY" \
--entrypoint n8n n8nio/n8n:2.40.7 import:entities --inputDir=/exports --truncateTables
# 3. Move the execution id sequence past the imported rows
psql -U n8n -d n8n -c "SELECT setval(pg_get_serial_sequence('execution_entity', 'id'), (SELECT max(id) FROM execution_entity));"
- Execution history is left out by default. Add
--includeExecutionHistoryDataTables=true(our small instance: 176 KB without, 184 KB with). DB_TYPE=postgresdoes not fail. n8n logsInvalid value for DB_TYPE - Invalid enum value. Expected 'sqlite' | 'postgresdb', received 'postgres'. Falling back to default value.and starts a fresh SQLite database, so your import seems to vanish.- The first new execution failed with
QueryFailedError: duplicate key value violates unique constraint "pk_e3e63bbf986767844bbe1166d4e", because the id sequence was still at 1. Step 3 fixed it, and the imported credential worked. - A different encryption key is refused:
Mismatching encryption keys. The encryption key in the settings file /home/node/.n8n/config does not match the N8N_ENCRYPTION_KEY env var.Copy the old key from/home/node/.n8n/configfirst.
If you only need Postgres and not queue mode, you can stop after step 3: regular mode runs on Postgres too, and our n8n template starts on its own Postgres from the first boot.
Redis for n8n queue mode: the settings that matter
Redis held at most 3.4 MB in any run, so size is not the issue: persistence and eviction are. Without persistence, a Redis restart lost every waiting job in our test; with AOF, none.
Redis eviction policy: why it must be noeviction
n8n 2.40.7 queues through the Bull 4 library, whose jobs live in ordinary Redis keys (bull:jobs:wait, bull:jobs:active, one hash per job). If Redis has a memory limit and an evicting policy, it can delete those keys. Set it explicitly:
redis-server --maxmemory-policy noeviction
With allkeys-lru set on purpose, neither n8n nor Redis logged a warning, so nothing tells you the setting is wrong until a key disappears. (We didn’t fill Redis to its limit, so eviction itself wasn’t reproduced.)
Redis persistence: what survives a restart
We queued 20 executions with no worker running, so they waited in Redis, then killed Redis with SIGKILL and started it again:
| Redis setting | Waiting before the kill | Waiting after restart | Outcome once a worker came back |
|---|---|---|---|
--appendonly yes --appendfsync everysec | 20 | 20 | All 20 ran, success |
--appendonly no --save '' | 20 | 0 | All 20 marked crashed |
With AOF persistence on, 20 of 20 waiting n8n executions survived a Redis kill and ran afterwards. Without it, they show as crashed (the rows live in Postgres) and never run again on their own.
While Redis was down, main logged Lost Redis connection. Trying to reconnect in 1s... (0s/10s), then Unable to connect to Redis after trying to connect for 10s, and exited. restart: unless-stopped brought it back 4 s after Redis returned. Webhooks sent during the outage got no answer.
How much memory Redis used
| Load | Redis used memory |
|---|---|
| Idle (1 to 4 workers) | 2.1 to 2.4 MB |
| 20 req/s, up to about 1,000 jobs waiting | 3.0 to 3.3 MB |
| 50 req/s, up to about 1,400 jobs waiting | 3.1 to 3.4 MB |
A larger backlog would use more (our load generator capped open requests at 1,000), but execution data lives in Postgres, not Redis.
Postgres connections for n8n workers: the pool size math
Plan connections with this formula:
connections = (main pool + 1) + workers × worker pool + headroom (psql, backups, monitoring)
In plain terms: with n8n’s default pool (DB_POSTGRESDB_POOL_SIZE=2), main holds 3 Postgres connections and each worker 2. That held in every run; only 4 workers at 50 requests/s went over, once, by one:
| Setup | Connections from n8n (peak, pg_stat_activity) |
|---|---|
| Regular mode | 3 |
| Queue, 1 worker | 5 |
| Queue, 2 workers | 7 |
| Queue, 4 workers | 11 (12 once) |
Queue, 4 workers, DB_POSTGRESDB_POOL_SIZE=10 | 44 |
With the defaults that is 13 for 4 workers, far below Postgres’s default max_connections of 100. Raising the pool to 10 on 4 workers took it to 44.
Aziz on PgBouncer: “I wouldn’t put PgBouncer in front of n8n on one server with a handful of workers. Even 4 workers with raised pools stayed at 44 connections against Postgres’s 100. I’d add it when connections come from several servers. If you do, transaction pooling works: main and 2 workers behind PgBouncer 1.24.1 ran 200 of 200 webhooks with no errors, on 6 server connections. That was a short functional test, not part of the benchmark.”
Execution data growth and pruning
Our tiny workflow stored 3.1 to 3.8 KB per execution: 15 to 20 MB per setup’s three runs. With EXECUTIONS_DATA_PRUNE=true (the default), n8n deletes executions older than EXECUTIONS_DATA_MAX_AGE (336 hours) or beyond EXECUTIONS_DATA_PRUNE_MAX_COUNT (10,000).
At about 550 executions a minute, 10,000 is only 18 minutes of history. Decide which limit you hit first; our file sets 168 hours and keeps the 10,000 cap. Real payloads are bigger than ours, so measure yours.
What breaks in n8n queue mode: 6 failure drills
In n8n queue mode, a worker that dies or stops slowly loses the executions it was running: n8n marks them failed and does not retry them. Everything else we broke recovered on its own. We ran these drills locally in Docker (29.8.0) with the same Compose file, n8n 2.40.7, 1 to 2 workers at concurrency 10.
| What we broke | What happened |
|---|---|
| Killed a worker mid-execution | Its 4 running executions failed after about 70 s; the other worker carried on |
| Started a worker with another encryption key | It refused to start |
| Restarted Redis with 20 jobs waiting | AOF kept all 20; without it, all 20 crashed |
| Restarted Postgres under load | 8 of 361 requests failed; everything recovered on its own |
| Used filesystem binary data without a shared volume | The worker couldn’t read the file (HTTP 500) |
| Stopped a worker normally | Executions longer than 30 s were cut off |
1. Kill a worker mid-execution
Four executions of a workflow with a 50 s Wait were running on worker-1; we sent it SIGKILL (docker kill).
- They showed
running, then about 70 s later all 4 turned toerror, not retried on the other worker. Main logged:
Problem with execution 2: This execution failed to be processed too many times and will no longer retry. To allow this execution to complete, please break down your workflow or scale up your workers or adjust your worker settings.. Aborting
Error: job stalled more than maxStalledCount (execution 2)
- The other worker kept serving new executions.
- Docker did not restart the killed worker:
docker killcounts as a manual stop forrestart: unless-stopped, so it stayedexited (137).
2. Worker with a different encryption key
In n8n 2.40.7 the worker does not start at all, so it cannot run anything with the wrong key:
Error: Deployment key 'signing.hmac' cannot be read with this instance encryption key
Worker exiting due to an error.
The other worker ran all 8 test executions that used a credential, all success. Check this line if a new worker never shows up as ready.
3. Redis restart with jobs waiting
With AOF on, 20 of 20 waiting executions survived a SIGKILL of Redis; with persistence off, all 20 ended as crashed. Main exits after 10 s without Redis and needs a restart policy to come back. The logs and table are in the Redis persistence section.
4. Postgres restart during load
We restarted Postgres at 4 requests a second. It was back in 1 s and main was ready again in 3 s. 8 of 361 requests failed: 7 with 503 {"code":503,"message":"Database is not ready!"} and 1 HTTP 500. Main and the worker logged Postgres pool client error: terminating connection due to administrator command, then Database connection recovered, with no manual restart.
5. Binary data on the filesystem without a shared volume
With N8N_DEFAULT_BINARY_DATA_MODE=filesystem and no shared volume, a 300 kB upload read by a Code node (this.helpers.getBinaryDataBuffer) landed on main’s disk. The worker couldn’t read it, and the caller got {"message":"Error in workflow"} (HTTP 500). The node error is only the missing path:
{"level":"info","shouldReport":false,"tags":{},"extra":{"filePath":"workflows/<workflow id>/executions/temp/binary_data/<uuid>"}}
With the variable unset, n8n 2.40.7 stored the upload in Postgres (id: database:…) and the worker read all 300,000 bytes, locally and on Selfhost.dev. That’s by design: unset, n8n picks database in queue mode and filesystem in regular mode (binary-data.config.ts in n8n 2.40.7), and n8n’s docs now say so. Filesystem mode needs main and every worker on one shared volume. Database mode takes files up to 512 MiB (N8N_BINARY_DATA_DATABASE_MAX_FILE_SIZE).
6. Graceful shutdown
We stopped a worker normally (docker stop, SIGTERM, with the Compose stop_grace_period: 60s) while it ran two 20 s and two 50 s executions.
Waiting for 2 active executions to finish... (execution IDs: 7, 8)
Shutdown timed out after 30 seconds
process exited after 30s
The 20 s executions finished; the 50 s ones were cut off and marked error. n8n’s N8N_GRACEFUL_SHUTDOWN_TIMEOUT (default 30 s) decided, not Docker’s 60 s, so raise both above your longest execution.
How to monitor n8n queue mode
Turn on n8n’s queue metrics on main and watch three numbers: jobs waiting, the runner containers’ CPU and main’s memory. Those moved first in every run that went wrong.
On main:
N8N_METRICS=true
N8N_METRICS_INCLUDE_QUEUE_METRICS=true # updated every N8N_METRICS_QUEUE_METRICS_INTERVAL (default 20 s)
GET /metrics on main then includes:
n8n_scaling_mode_queue_jobs_waiting 520
n8n_scaling_mode_queue_jobs_active 20
n8n_scaling_mode_queue_jobs_completed 5436
n8n_scaling_mode_queue_jobs_failed 0
That snapshot is from the 2-worker run at 50 requests/s: active = 20 is exactly 2 workers × concurrency 10, so the workers were full. /metrics has no login and sits on main’s public port, so expose it only to your monitoring server.
Also watch worker /healthz and /healthz/readiness (with QUEUE_HEALTH_CHECK_ACTIVE=true), redis-cli LLEN bull:jobs:wait for the queue without n8n, and executions marked error or crashed.
The 3 numbers to alert on
| Alert on | Threshold we would set | What we saw |
|---|---|---|
n8n_scaling_mode_queue_jobs_waiting | Above 0 and rising for 5 minutes | Healthy runs drained to 0; overloaded runs climbed to about 1,000 |
| Runner container CPU | Above 90% of one core for 5 minutes (regular mode), or the whole server above 85% (queue mode) | Regular mode’s runner at 100% of one core while 3 cores idled; 2 workers ran at 3.5 of 4 cores with no errors; 4 workers at 3.6 cores began failing |
503 Database is not ready! from main | Any, sustained over 1 minute | Only when 4 workers overloaded 4 vCPU, and for 3 s during a Postgres restart |
Tune these once you know your normal queue depth. In regular mode, also alert on main’s memory: it went from 0.35 GB to 6.9 GB in about 3 minutes.
Field notes: what our engineer got wrong the first time
From Mohammad Aziz’s build log, in his words:
- “I named the services
postgresandredis. Main came up fine, both workers did not:[Redis client] WRONGPASS invalid username-password pair or user is disabled.andpassword authentication failed for user "n8n". Our own Postgres logged no failed login, which was the clue: on a Coolify-based host every container also joins the sharedcoolifynetwork, wherepostgresandredisare the platform’s own. Renaming them fixed it. It cost about 40 minutes, partly because I first blamed my YAML anchors.” - “I gave the runners no healthcheck. Everything else was healthy, but the runners reported
running:unknownand the platform failed the whole service after 10 minutes. Onewgethealthcheck per runner fixed it.” - “The first request after a quiet minute was slow. The task runner shuts itself down after 15 s idle (
N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT=15). The first Code node after idle took 2,709 ms instead of 187 ms, and the first webhook answered in 7.0 s instead of about 1.1 to 1.6 s.”
n8n queue mode checklist
Ten checks before the first production webhook, each from a test above:
- Postgres with
DB_TYPE=postgresdbexactly (postgressilently falls back to SQLite). - One
N8N_ENCRYPTION_KEYon main and every worker. - Every image pinned; main starts after Postgres and Redis, workers after main.
- One task runner per n8n process, pointed at its own process, with a healthcheck.
- Redis with
noevictionand--appendonly yes. - Postgres connections: (main pool + 1) + workers × pool, under
max_connections. --concurrencyat 10, and no more workers than your cores can feed (2 per 4 vCPU in our test).- Binary data mode unset or
database, notfilesystemwithout a shared volume. - Pruning set for your volume; shutdown timeouts above your longest execution.
- Alerts on jobs waiting, runner CPU and
Database is not ready!;/metricsclosed to the internet.
The tested file already covers all 10.
Start with a stack that passes every check, no card needed
n8n queue mode FAQ
How many n8n workers should I run on one server?
As many as your CPU cores can feed, leaving room for main and Postgres. On a 4 vCPU server running Code-heavy workflows, 2 workers answered 519 executions a minute at 50 requests a second with no errors. 4 workers answered no more at the same load and added 1,013 errors.
Can n8n queue mode run on one server?
Yes. Every number in this post comes from main, 2 workers, Redis and Postgres on one 4 vCPU / 8 GB server. On one server, queue mode spreads executions across CPU cores, but it doesn’t give you high availability: if the server goes down, everything does.
What is the default worker concurrency in n8n?
10 executions per worker (n8n worker --concurrency=10). In n8n 2.x the task runner has its own limit, 5 in n8n’s one-click template. In our test, raising both to 10 or 20 made no difference beyond noise, while lowering both to 5 cost throughput at 50 requests a second.
Does n8n queue mode need S3 for binary data?
No. In queue mode, n8n stores binary data in Postgres by default, and in our test a worker read a 300 kB upload from it. Database mode takes files up to 512 MiB. S3 needs a Business or Enterprise licence. Filesystem mode only works if main and every worker share one volume.
Do manual executions run on workers?
Not by default. OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS defaults to false, so runs from the editor’s Execute button stay on main, while webhook and trigger runs go to workers. Set it to true on main, as our Compose file does, if you test heavy workflows from the editor.
Does N8N_CONCURRENCY_PRODUCTION_LIMIT work in queue mode?
Yes, but per worker. Per n8n’s docs, when it’s set to anything other than -1, each worker takes its limit from it instead of --concurrency. It isn’t a total across workers. In regular mode it caps production runs inside main; a limit of 10 kept our main at 674 MB.
Do n8n workers need the same encryption key?
Yes. In n8n 2.40.7 a worker with a different N8N_ENCRYPTION_KEY stops at boot with Deployment key 'signing.hmac' cannot be read with this instance encryption key. Copy the key from main’s /home/node/.n8n/config into every worker before you start them, and never change it afterwards.
Does n8n queue mode need an Enterprise licence?
No. Queue mode itself isn’t licensed; we ran it on the free Community image. Multi-main setup and the Settings > Workers view need a licence, and external binary storage (S3) is for Business and Enterprise plans. For the rest, see what the free Community edition includes.
The short version
n8n queue mode pays off once one task runner can’t keep up, and not before:
- CPU and memory comfortable, editor responsive: stay in regular mode.
- A few heavy workflows spiking at once: set
N8N_CONCURRENCY_PRODUCTION_LIMITfirst. - One runner pinned at a full core: switch to queue mode, starting with 2 workers per 4 vCPU at concurrency 10.
- The whole server near full CPU: add cores, not workers.
Still below one busy core? Run n8n on a server we keep running, no Redis to look after. Past it? Put main, workers and Redis on one server we set up.
Keep reading:
Based on this page: ·
On now or still deciding?
What's the bill you're looking at?
Roughly how much a month, all in?
Matched to RDS, we bill 3.0x less in ap-south-1 (Mumbai) and 2.1x less in us-east-1.
2 vCPU / 4 GB with 20 GB: $24.54/mo in Mumbai, $35.27/mo in us-east-1, against an estimated $73.75/mo on RDS.
See a real RDS bill, before and after →Neon meters compute hours and sleeps. We bill one fixed hourly rate and never sleep.
{price} Same number in a quiet month and a launch month.
Price your size →Two ways off the Supabase bill and you can keep the Supabase stack.
Self-host Supabase on a managed server: a European 8 GB server is $0.03/hr or move just the database to a dedicated Postgres. {price}
How self-hosted Supabase works here →An enterprise client is moving production ClickHouse to us at up to 60% less.
Worked example: off ClickHouse Cloud Scale to always-on managed ClickHouse, $891.86 to $364.03 a month, 59%.
See the ClickHouse bill, before and after →A PaaS bills per service. A project server is one bill for everything on it.
Worked example: a studio consolidated client hosting onto project servers, $390.00 to $82.66 a month, 78%.
See that bill, before and after →Managed PostgreSQL from $8.10 a month in Mumbai. Dedicated Postgres or MySQL on AWS, with restore, pooling and Multi-AZ failover when you want it.
{price} Postgres and MySQL price the same.
Price your size →Managed PostgreSQL from $8.10 a month in Mumbai. Dedicated Postgres or MySQL on AWS, with restore, pooling and Multi-AZ failover when you want it.
{price}
Price your size →Managed PostgreSQL from $8.10 a month in Mumbai. Dedicated Postgres or MySQL on AWS, with restore, pooling and Multi-AZ failover when you want it.
{price} Pay-as-you-go credits, top up from $5, no plan tiers.
Price your size →Most setups map onto two shapes: dedicated databases on AWS and a project server for everything else.
{price} Project servers from about $0.02/hr in Europe.
Price your size →Under $200 a month, the calculator beats a human reply. Price it there first.
What's it for?
Where do your users mostly sit?
Dedicated managed Postgres or MySQL, with point-in-time restore, pooling and Multi-AZ failover when you want it.
{region} If you need scale-to-zero or instant branching, Neon fits better than we do.
What managed Postgres includes →Managed ClickHouse for events at volume or TimescaleDB on managed Postgres for time-series next to your app data.
Worked example: off ClickHouse Cloud Scale, $891.86 to $364.03 a month, 59%. {region}
See the ClickHouse bill, before and after →pgvector on managed Postgres: one database instead of a second vendor.
{region} TimescaleDB is one click away on the same instance if you also have time-series.
When a dedicated vector DB is worth it →A project server from about $0.02/hr in Europe: push to GitHub and it deploys, several apps and their databases on one box.
Auto-deploy on push, PR previews, custom domains. The $5 welcome credit covers the start of it, no card needed; it bills by the hour.
How Projects work →Project servers: many sites per server, one bill.
Worked example: a studio consolidated client hosting, $390.00 to $82.66 a month, 78%.
See that bill, before and after →Most things fit dedicated databases on AWS plus a project server for the apps.
{region}
See it in the live demo →What are you trying to do?
Which editor?
We migrate you, free, on every plan size.
An engineer runs it with you: match the instance, replicate or dump and restore, test the restore, cut over.
See one migration, step by step →The Supabase stack, one click, on a server of your own.
One click from the template. A European 8 GB server is $0.03/hr. Nothing to build or wire up.
Self-hosted Supabase in one click →Paste one config and your editor can run the whole backend.
Run it once, sign in when the browser opens and all 269 tools register.
An hourly instance you stop when you are done.
Restore a snapshot into a second instance, point staging at it and stop it when idle: only its storage bills while it is stopped.
Price a small instance →Push to GitHub and it's live: auto-deploy, PR previews, custom domains.
A project server from about $0.02/hr in Europe runs several apps and their databases.
Deploy guides by framework →The one that matters most:
Managed PostgreSQL from $8.10 a month in Mumbai. Project servers from about $0.02 an hour in Europe.
The smallest dedicated Postgres, a 1 GB t4g.micro with 1 GB of storage, is $8.10 a month in ap-south-1 (Mumbai) and $10.55 in us-east-1; the $5 welcome credit goes toward it. Pay-as-you-go credits, top up from $5, no tiers.
Price your size →When production needs help, you talk to the engineers who run it and a founder reads every request.
Outages, restores, performance issues and migrations reach the people operating the platform. No response-time promise or uptime percentage we cannot prove.
How support and recovery work →Failover, point-in-time restore and backups cover the common ways a database fails.
Multi-AZ failover is a toggle on Postgres, MySQL, Redis and ClickHouse and a cluster you pick at create on OpenSearch; Postgres and MySQL add point-in-time restore and every engine gets automated backups, live metrics and alerts.
The reliability and recovery details →We migrate you, free. An engineer plans and runs the move with you.
Match the instance, replicate or dump and restore, test the restore, cut over. Any plan size, no extra cost.
See one migration, step by step →Run it in your own AWS account with BYOC, in the region you need.
Encryption at rest on every managed instance; client TLS is a switch on PostgreSQL, MySQL and ClickHouse and always on for OpenSearch. We do not hold SOC 2 or HIPAA today and we will say so before you spend an hour.
What we can and cannot certify →Fair enough. The live demo is the fastest way to see it.
Or claim $5 to start, no card needed.
Watch the live demo →Our founder
You've already sent us your setup from this browser. A founder will reply to it; no need to send it twice.
Got it. I'll reply to within two working days, from my own inbox.
Noted. One note when it changes, nothing else.
Ship the app you just read about.
Deploy straight from GitHub onto a dedicated server we run for you, with auto-deploy on push and preview environments. Pay by the hour from about $0.02 in Europe, with no surprise invoices. No DevOps. Limited-time offer: get $5 in free credit at signup, no card needed.
Based on this page: ·
On now or still deciding?
What's the bill you're looking at?
Roughly how much a month, all in?
Matched to RDS, we bill 3.0x less in ap-south-1 (Mumbai) and 2.1x less in us-east-1.
2 vCPU / 4 GB with 20 GB: $24.54/mo in Mumbai, $35.27/mo in us-east-1, against an estimated $73.75/mo on RDS.
See a real RDS bill, before and after →Neon meters compute hours and sleeps. We bill one fixed hourly rate and never sleep.
{price} Same number in a quiet month and a launch month.
Price your size →Two ways off the Supabase bill and you can keep the Supabase stack.
Self-host Supabase on a managed server: a European 8 GB server is $0.03/hr or move just the database to a dedicated Postgres. {price}
How self-hosted Supabase works here →An enterprise client is moving production ClickHouse to us at up to 60% less.
Worked example: off ClickHouse Cloud Scale to always-on managed ClickHouse, $891.86 to $364.03 a month, 59%.
See the ClickHouse bill, before and after →A PaaS bills per service. A project server is one bill for everything on it.
Worked example: a studio consolidated client hosting onto project servers, $390.00 to $82.66 a month, 78%.
See that bill, before and after →Managed PostgreSQL from $8.10 a month in Mumbai. Dedicated Postgres or MySQL on AWS, with restore, pooling and Multi-AZ failover when you want it.
{price} Postgres and MySQL price the same.
Price your size →Managed PostgreSQL from $8.10 a month in Mumbai. Dedicated Postgres or MySQL on AWS, with restore, pooling and Multi-AZ failover when you want it.
{price}
Price your size →Managed PostgreSQL from $8.10 a month in Mumbai. Dedicated Postgres or MySQL on AWS, with restore, pooling and Multi-AZ failover when you want it.
{price} Pay-as-you-go credits, top up from $5, no plan tiers.
Price your size →Most setups map onto two shapes: dedicated databases on AWS and a project server for everything else.
{price} Project servers from about $0.02/hr in Europe.
Price your size →Under $200 a month, the calculator beats a human reply. Price it there first.
What's it for?
Where do your users mostly sit?
Dedicated managed Postgres or MySQL, with point-in-time restore, pooling and Multi-AZ failover when you want it.
{region} If you need scale-to-zero or instant branching, Neon fits better than we do.
What managed Postgres includes →Managed ClickHouse for events at volume or TimescaleDB on managed Postgres for time-series next to your app data.
Worked example: off ClickHouse Cloud Scale, $891.86 to $364.03 a month, 59%. {region}
See the ClickHouse bill, before and after →pgvector on managed Postgres: one database instead of a second vendor.
{region} TimescaleDB is one click away on the same instance if you also have time-series.
When a dedicated vector DB is worth it →A project server from about $0.02/hr in Europe: push to GitHub and it deploys, several apps and their databases on one box.
Auto-deploy on push, PR previews, custom domains. The $5 welcome credit covers the start of it, no card needed; it bills by the hour.
How Projects work →Project servers: many sites per server, one bill.
Worked example: a studio consolidated client hosting, $390.00 to $82.66 a month, 78%.
See that bill, before and after →Most things fit dedicated databases on AWS plus a project server for the apps.
{region}
See it in the live demo →What are you trying to do?
Which editor?
We migrate you, free, on every plan size.
An engineer runs it with you: match the instance, replicate or dump and restore, test the restore, cut over.
See one migration, step by step →The Supabase stack, one click, on a server of your own.
One click from the template. A European 8 GB server is $0.03/hr. Nothing to build or wire up.
Self-hosted Supabase in one click →Paste one config and your editor can run the whole backend.
Run it once, sign in when the browser opens and all 269 tools register.
An hourly instance you stop when you are done.
Restore a snapshot into a second instance, point staging at it and stop it when idle: only its storage bills while it is stopped.
Price a small instance →Push to GitHub and it's live: auto-deploy, PR previews, custom domains.
A project server from about $0.02/hr in Europe runs several apps and their databases.
Deploy guides by framework →The one that matters most:
Managed PostgreSQL from $8.10 a month in Mumbai. Project servers from about $0.02 an hour in Europe.
The smallest dedicated Postgres, a 1 GB t4g.micro with 1 GB of storage, is $8.10 a month in ap-south-1 (Mumbai) and $10.55 in us-east-1; the $5 welcome credit goes toward it. Pay-as-you-go credits, top up from $5, no tiers.
Price your size →When production needs help, you talk to the engineers who run it and a founder reads every request.
Outages, restores, performance issues and migrations reach the people operating the platform. No response-time promise or uptime percentage we cannot prove.
How support and recovery work →Failover, point-in-time restore and backups cover the common ways a database fails.
Multi-AZ failover is a toggle on Postgres, MySQL, Redis and ClickHouse and a cluster you pick at create on OpenSearch; Postgres and MySQL add point-in-time restore and every engine gets automated backups, live metrics and alerts.
The reliability and recovery details →We migrate you, free. An engineer plans and runs the move with you.
Match the instance, replicate or dump and restore, test the restore, cut over. Any plan size, no extra cost.
See one migration, step by step →Run it in your own AWS account with BYOC, in the region you need.
Encryption at rest on every managed instance; client TLS is a switch on PostgreSQL, MySQL and ClickHouse and always on for OpenSearch. We do not hold SOC 2 or HIPAA today and we will say so before you spend an hour.
What we can and cannot certify →Fair enough. The live demo is the fastest way to see it.
Or claim $5 to start, no card needed.
Watch the live demo →Our founder
You've already sent us your setup from this browser. A founder will reply to it; no need to send it twice.
Got it. I'll reply to within two working days, from my own inbox.
Noted. One note when it changes, nothing else.