Best n8n Hosting Platforms in 2026: A Self-Hoster's Guide
You've read the pricing page, done the arithmetic, and decided to self-host n8n. Fine choice. The next decision is less fun: n8n is not a static site and it is not a stateless API, and most of the hosting options you'd reach for by reflex are wrong for it in ways you won't discover until a webhook fires at 3am and nobody is home.
This is a 2026 roundup of where to actually run it: n8n Cloud, a plain VPS, Coolify, Railway/Render-style app platforms, Fly.io, Kubernetes in queue mode, and PandaStack — which I built, so weight that accordingly. Requirements first, because the requirements are what eliminate options.
What n8n actually demands from a host
Six properties. Each one rules something out, and together they explain why so many self-hosted n8n stories end with someone reinstalling on a boring VM after a month of cleverness.
It's stateful, and SQLite is a decision you only get to make once
n8n keeps your workflows, execution history, and credentials in a relational database. It will happily use SQLite, and SQLite will happily work — through the demo, the first few workflows, the first month. Then history grows, workflows run concurrently, the container restarts on an ephemeral disk, and you learn that SQLite here is a development choice that matures, over about six months, into an incident.
Use Postgres from day one, because migrating later means moving live credentials between databases while triggers are firing. That reshapes the hosting question: you're not hosting a container, you're hosting a container plus a database somebody has to back up and monitor. Set a retention policy on execution data at the same time, before your own history becomes the largest table you own.
Webhooks need a stable URL that is awake
Most real workflows start with an inbound HTTP call: Stripe, GitHub, a form provider, a CRM. You register that URL once, in someone else's dashboard, and it has to keep working for years. So the hostname must survive deploys, and the endpoint must answer at any hour with no human in the loop.
This is where "just run it as a serverless function" falls apart for the main instance — not because of cold start, but because that process owns the workflow state, the trigger registration, and the editor UI. It's also where a misconfigured WEBHOOK_URL bites: if n8n doesn't know its own public address, it hands your integrations a localhost URL and every callback disappears into a 404 you never see.
Executions can run for an embarrassingly long time
A workflow that polls an API until a job finishes, waits on a human approval, or batches ten thousand rows through a rate-limited endpoint is normal usage, and it's hostile to platforms built around short request lifetimes. Check two numbers on any candidate: the maximum request duration through its ingress, and how it treats a process that is alive but doing nothing visible for ten minutes.
Queue mode is the real scaling story
One container is fine until it isn't. The supported way past that is queue mode: main keeps the UI, webhooks, and schedule, and pushes executions onto Redis where a pool of workers picks them up. That's three process types plus Postgres, sharing one encryption key and one database. So: can this platform run several long-lived process types with different commands and scale one independently? Some can trivially. Some would rather you didn't.
The box holds every API key your business owns
A working instance accumulates OAuth tokens and keys for your CRM, payment processor, cloud account, and internal admin API. They're encrypted at rest with a key n8n reads from its environment, which makes that key and the isolation of the host underneath a security decision rather than a hosting preference. "Cheap shared hosting" and "the crown jewels of our integrations" should not appear in the same diagram.
The elephant: n8n is an untrusted-code execution engine in a trench coat
The Code node runs arbitrary JavaScript. The Execute Command node runs arbitrary shell. That's a feature — it's most of why people pick n8n over the click-only tools — and it means a self-hosted instance is architecturally a code execution platform wearing a business-automation trench coat.
"But I write all the workflows myself" holds right up until it doesn't: you grant editor access to the ops team, or a client, or you let an LLM author steps because that's the whole promise of 2026 automation. Now unreviewed code runs in the same process that holds every credential you own, on a host that can reach your internal network. n8n has been moving execution toward separate task runners and offers restrictions on what a Code node may import — check its current docs, this area is active — but the default boundary is a process on a shared kernel, and a container is a polite suggestion to the kernel rather than a wall.
Two honest responses: bound the blast radius of the whole instance with something stronger than a container, or push risky steps out of the n8n process into disposable sandboxes. Usually both.
The baseline to compare everything against
Before shopping, know what a correct minimal deployment looks like. Every platform below is really a different answer to "who operates this file."
# docker-compose.yml -- n8n + Postgres, the minimum that isn't a liability.
services:
postgres:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
interval: 10s
timeout: 5s
retries: 10
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- "127.0.0.1:5678:5678" # put a TLS-terminating proxy in front
environment:
# Lose this and every stored credential is unrecoverable. Back it up
# somewhere that is NOT the same disk as the database.
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
# The public address third parties register. If this is wrong, every
# inbound webhook 404s and nothing in your logs says why.
WEBHOOK_URL: https://n8n.example.com/
N8N_HOST: n8n.example.com
N8N_PORT: 5678
N8N_PROTOCOL: https
GENERIC_TIMEZONE: Europe/Berlin
# Execution history grows without bound otherwise.
EXECUTIONS_DATA_PRUNE: "true"
EXECUTIONS_DATA_MAX_AGE: 336 # hours (14 days)
volumes:
- n8ndata:/home/node/.n8n
volumes:
pgdata:
n8ndata:Once one container isn't enough, the shape changes rather than grows — main, Redis, and workers you scale independently, all sharing the same key and database:
# Queue mode: main owns UI + webhooks, workers execute.
x-n8n-env: &n8n_env
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: redis
QUEUE_BULL_REDIS_PORT: 6379
QUEUE_HEALTH_CHECK_ACTIVE: "true"
# Same key + same DB on main and every worker, or nothing decrypts.
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
WEBHOOK_URL: https://n8n.example.com/
services:
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redisdata:/data
n8n-main:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
environment: *n8n_env
ports:
- "127.0.0.1:5678:5678"
depends_on: [redis, postgres]
n8n-worker:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
command: worker --concurrency=10
environment: *n8n_env
depends_on: [redis, postgres]
deploy:
replicas: 3
volumes:
redisdata:One always-on front door, N interchangeable workers, a database and a Redis. That's the thing you're shopping for a home for.
The options, with where each one hurts
Seven realistic homes, described qualitatively. Feature sets and pricing move; confirm the specifics against each provider's current documentation before deciding on this basis.
n8n Cloud — the do-nothing baseline
Start here, even if you plan to leave. The vendor's own hosted offering handles the database, TLS, upgrades, the webhook URL, and the queue mode you'd otherwise design yourself. "We ran on Cloud for two months while we learned what we actually need" is a strategy, not a failure.
Where it hurts: it's the thing you're reading this article to escape. Usually cost as execution volume grows, data residency rules, needing to reach services on a private network, or wanting control of the runtime. If none apply, close this tab and go build something.
A plain VPS with Docker Compose — the boring correct answer
One Linux box, the compose file above, a reverse proxy for TLS, a firewall, automated Postgres backups. This is the most common self-hosted n8n deployment in the world and it isn't a compromise: always-on by nature, no request timeout except the one you configure, and upgradable to queue mode in place.
Where it hurts: everything is yours. Patching, Docker upgrades, certificate renewal, disk monitoring, and the one that actually kills people — verified Postgres backups. A backup you have never restored is a hypothesis. There's also no isolation beyond the container: Code node, credentials, and database share one kernel.
Coolify and self-hosted PaaS — a control panel over that same box
Coolify and its neighbours give you a deploy UI, app templates, TLS automation, and managed database containers on servers you own. The compose file becomes a form, certificates stay renewed, and there's a redeploy button that isn't SSH.
Where it hurts: the control plane is another stateful system you operate, sitting in the path of your own recovery. Its "managed" Postgres is typically a container on the same host, so backup discipline is still yours, and isolation is unchanged from the VPS case. A panel that makes deploying easy also makes it easy to pile twelve services onto a box sized for three.
Railway, Render and friends — app platforms
Push-to-deploy platforms with managed Postgres and Redis add-ons solve the database, TLS, the stable hostname, and multi-service deploys — four of the six requirements with no infrastructure code. Queue mode maps cleanly onto one web service, one worker service, one Redis.
Where it hurts: read the ingress timeout and the persistent-storage story carefully, because they vary by platform and plan, and long executions are exactly where the gaps show. Cheaper tiers that sleep idle services are fatal for a webhook receiver. Isolation is container-grade on shared infrastructure, and the economics that made you leave Cloud can follow you here.
Fly.io — VMs that feel like an app platform
Fly sits between the VPS and the PaaS: VM-backed instances with a deploy pipeline, multi-process apps, volumes, and private networking between services. Main and worker process groups against a Redis is a natural fit, and the private network helps when n8n must reach your other services without going out to the public internet.
Where it hurts: you carry more of the database responsibility than a fully managed provider would leave you. Auto-stop needs deliberate configuration when webhooks must be answered immediately — waking on request is great for a website and a nuance for a payment provider with a short retry policy. Confirm current auto-start, volume, and Postgres behavior in Fly's docs.
Kubernetes with queue mode — for actual scale
If n8n is a production dependency for multiple teams and you already run Kubernetes, this is the endgame: a Deployment for main, a horizontally scaled Deployment for workers, Redis, managed cloud Postgres, secrets from a real secrets manager, an Ingress with a timeout you chose, and network policies per workload.
Where it hurts: it's Kubernetes. Don't build a cluster to host one automation tool — the operational surface dwarfs the thing you're deploying. And pod-level isolation is still shared-kernel isolation, so this solves scaling without touching the Code-node problem unless you add a sandboxed runtime class.
PandaStack — an instance per microVM, with the database beside it
My own project, so here's the bet rather than a pitch. Each workload runs as a Firecracker microVM with its own guest kernel, KVM-isolated, on its own network namespace and tap device. Managed Postgres lives on the same substrate — a database is itself a microVM with a durable volume, created in 30–90 seconds — so n8n and its database are one deployment, not two vendors. Sandboxes restore from a baked snapshot on every create (179ms p50, ~203ms p99), which is what makes disposable per-execution sandboxes practical rather than theoretical.
Two things follow. Idle: n8n spends most of its life waiting between webhook bursts, and scale-to-zero via snapshot-restore means the quiet stretches needn't be billed like busy ones. Blast radius: when a Code node does something regrettable, the boundary is a guest kernel and a hypervisor, not a namespace on a kernel your other services share.
Where it hurts: scale-to-zero is a trade, so a webhook needing zero warm-up means keeping the front door always-on and letting only execution sandboxes come and go. It's a newer platform, the community's stock of n8n recipes lives elsewhere, and if your situation is "one container, low volume, workflows I wrote myself," a boring VPS is the right answer and I'd rather you use one.
Side by side
- Managed Postgres included — n8n Cloud: yes, invisible. VPS: no, a container you back up. Coolify: a managed container on your own host. Railway/Render: yes, first-class add-on. Fly.io: available, more your responsibility than a fully managed cloud DB. Kubernetes: whatever your cloud offers. PandaStack: yes, each database its own microVM with a durable volume.
- Webhook always-on — n8n Cloud: yes. VPS: yes, while the box is up. Coolify: yes. Railway/Render: yes on always-on tiers; cheaper tiers may sleep. Fly.io: yes, but auto-stop needs configuring. Kubernetes: yes. PandaStack: yes for the front door, executions scaling to zero.
- Long executions — n8n Cloud: the vendor's problem. VPS: unbounded, you own the proxy timeout. Coolify: same. Railway/Render: bounded by platform ingress timeouts — verify first. Fly.io: generally fine, confirm proxy behavior. Kubernetes: you set the Ingress timeout. PandaStack: TTL-bounded per sandbox, and you pick the TTL.
- Queue-mode workers — n8n Cloud: abstracted away. VPS: add services to the compose file. Coolify: one service per process type. Railway/Render: clean — web plus worker plus Redis. Fly.io: natural fit via process groups. Kubernetes: best-in-class, horizontally scaled worker Deployment. PandaStack: workers as separate microVMs against a shared Redis.
- Code-node isolation — n8n Cloud: the vendor's tenancy model, not yours. VPS: a container on your kernel. Coolify: a container on your kernel. Railway/Render: container-grade on shared infrastructure. Fly.io: VM-backed, stronger than a shared-kernel container. Kubernetes: pod-level, still shared-kernel without a sandboxed runtime. PandaStack: hardware-virtualized microVM with its own guest kernel.
- Idle cost — n8n Cloud: subscription regardless of activity. VPS: the box bills 24/7. Coolify: the box bills 24/7. Railway/Render: usage-shaped, but always-on is always on. Fly.io: auto-stop can cut idle if you accept wake latency. Kubernetes: you pay for nodes. PandaStack: scale-to-zero between bursts.
- Ops burden — n8n Cloud: near zero. VPS: all of it, including backups you must test. Coolify: less clicking, same responsibility, plus the panel. Railway/Render: low. Fly.io: moderate. Kubernetes: high unless you already run a cluster. PandaStack: managed substrate; you own workflow decisions, not hosts.
Getting the risky work out of the n8n process
Whatever you pick, adopt this the moment more than one person can edit workflows: replace the Code node with an HTTP Request node pointing at a small service that runs the snippet in a disposable sandbox and returns JSON. n8n keeps orchestrating; it stops being the thing that executes.
import json
from pandastack import Sandbox
def run_step(snippet: str, items: list[dict]) -> dict:
"""Called by an n8n HTTP Request node instead of a Code node.
The snippet never shares an address space with N8N_ENCRYPTION_KEY,
and never shares a network namespace with your internal services.
"""
with Sandbox.create(
template="code-interpreter",
ttl_seconds=120, # hard backstop on runaway code
metadata={"source": "n8n", "kind": "code-node"},
) as sbx:
sbx.filesystem.write("/workspace/items.json", json.dumps(items))
sbx.filesystem.write("/workspace/step.js", snippet)
r = sbx.exec(
"node /workspace/step.js < /workspace/items.json",
timeout_seconds=60,
)
if r.exit_code != 0:
return {"ok": False, "error": r.stderr[-4000:]}
return {
"ok": True,
"items": json.loads(r.stdout),
"duration_ms": r.duration_ms,
}
# The microVM is destroyed here. Whatever the snippet did to the
# filesystem, the process table, or its own kernel went with it.The cost is one HTTP hop and a sandbox create per risky step. The benefit is that "someone pasted a snippet from a forum into a Code node" stops being an incident class. It also composes with everything above: run n8n on a boring VPS and still push execution into isolated sandboxes.
How to choose, in the order that matters
- If you have no compliance, cost, or network-access reason to leave n8n Cloud, don't. Self-hosting is a bill you pay in engineering hours, and it's only worth it against a real constraint.
- If you're leaving for cost or data control, and workflows are authored only by people you'd give production SSH to, take a VPS with Docker Compose, Postgres, tested backups, and a reverse proxy. Add Coolify if you want a panel over it.
- If you'd rather not own an OS but do want a stable URL, managed Postgres, and a clean main/worker split, take a Railway/Render-style platform or Fly.io — and verify the ingress timeout and idle-sleep behavior against a genuinely long workflow first.
- If n8n is a production dependency for several teams and you already run Kubernetes, run it there in queue mode with managed cloud Postgres. If you don't already run Kubernetes, skip this step entirely.
- If non-engineers or LLMs author workflows, or you're multi-tenant, treat the Code node as untrusted code and pick isolation deliberately: microVM-per-instance, sandboxed execution steps, or both. This is independent of the four above.
- Whatever you pick, do three things on day one: Postgres not SQLite, N8N_ENCRYPTION_KEY in a secrets manager and backed up separately, and a restore you have actually performed rather than merely configured.
n8n's hosting difficulty isn't really about n8n. You're hosting a stateful, always-on, long-running service that holds every credential your business owns and executes arbitrary code on request. Pick infrastructure that takes that description seriously, and the rest is a compose file and a backup you remembered to test.
Frequently asked questions
What is the best way to host self-hosted n8n?
For most teams, a single Linux VPS running n8n and PostgreSQL under Docker Compose, behind a TLS-terminating reverse proxy with tested database backups, is the correct answer — it satisfies the always-on webhook requirement, imposes no request timeout you didn't choose, and upgrades to queue mode in place. Choose an app platform like Railway, Render, or Fly.io instead if you'd rather not own an operating system and can verify their ingress timeouts tolerate your longest workflow. Choose Kubernetes only if you already run a cluster and n8n is a production dependency for multiple teams. Choose a microVM platform when workflow authors are untrusted or you need stronger isolation for the Code node than a shared kernel provides.
Do I need PostgreSQL for self-hosted n8n, or is SQLite fine?
Use PostgreSQL from the start. SQLite works for evaluation and single-user experimentation, but it degrades under concurrent executions, it grows an execution-history table that becomes your largest data structure, and it ties your instance to one disk on one host — which makes any later migration a live move of encrypted credentials while triggers are firing. Set DB_TYPE=postgresdb with the DB_POSTGRESDB_* variables before you build anything real, and enable execution-data pruning so history doesn't grow unbounded. Whether the database is a container you back up yourself or a managed service is one of the biggest practical differences between hosting options.
Can I run n8n on a serverless platform?
Not the main instance, realistically. n8n's main process owns workflow state, trigger registration, and the editor UI, and it needs a stable public hostname that answers inbound webhooks at any hour — properties that fit a long-lived service rather than a per-request function. Long executions make it worse: workflows that wait on a human approval or poll an external API for minutes collide with short function lifetimes and proxy timeouts. Serverless does make sense around n8n rather than for it: a thin function can receive and buffer webhooks in front of the instance, and per-execution sandboxes can run individual risky steps on demand.
Is the n8n Code node safe to run on a shared host?
Treat it as arbitrary code execution, because that is what it is — the Code node runs JavaScript and the Execute Command node runs shell, in an environment that also holds your credential encryption key and usually has network access to internal services. That is acceptable when you personally author and review every workflow, and it stops being acceptable the moment you grant editor access to a wider group, serve multiple tenants, or let an LLM generate workflow steps. n8n has been moving code execution toward separate task runners and offers restrictions on what a Code node may import, so check its current documentation for what your version enforces by default. For a real boundary, either run the instance inside a hardware-virtualized microVM with its own guest kernel, or push the risky steps out to disposable sandboxes via an HTTP Request node.
What happens if I lose N8N_ENCRYPTION_KEY?
Every stored credential becomes permanently unrecoverable. The workflows and credential rows survive in the database, but the secrets inside them cannot be decrypted, so you re-authenticate every integration by hand — including OAuth connections whose original setup nobody wrote down. The mirror-image risk is just as serious: anyone holding both the key and a database dump has every API key your business owns. Generate the key once, store it in a real secrets manager, back it up separately from your database backups, and make sure your platform cannot silently regenerate it on redeploy, because restoring a database into an instance with a different key yields credentials that look correct in the UI and fail at runtime.
Keep reading
- Best managed Postgres providers (2026) — n8n's hardest hosting requirement is the database — here's where to put it.
- Best Coolify alternatives (2026) — If the self-hosted PaaS option appeals, this is the wider field around it.
- Sandboxing user-uploaded automation scripts — The full pattern behind pushing Code-node work into disposable sandboxes.
- Scale-to-zero app hosting, explained — Why the long idle stretches between webhook bursts don't have to be billed.
49ms p50 cold start. Fork, snapshot, and scale to zero.