The n8n Helm chart will deploy in about ten minutes. What takes longer is the Postgres instance, the Redis instance, the persistent volume, the ingress, the TLS certificate and the encryption key you must not lose.
There is a community-maintained Helm chart for n8n, it is well built, and it supports the full production topology: a main process, separate worker replicas, separate webhook processors, and Redis coordinating between them.
That topology is genuinely what a busy n8n installation needs. It is also considerably more infrastructure than most teams reaching for it realise, so this covers both the how and the whether.
Table of contents
- The chart and what it deploys
- Do not run production on the bundled SQLite
- Queue mode: what the extra pods buy
- The encryption key, and the mistake that eats credentials
- Persistence, ingress and the rest of the checklist
- Is Kubernetes the right place for this
- How this fits the rest of the stack
- FAQ
The chart and what it deploys
The widely used chart is community-maintained rather than official, published on Artifact Hub and installed the usual way. Its values.yaml is organised into sections: global settings, ingress, the main n8n app, workers, webhook processors, and Redis.
The design decision worth knowing before you read the values file is how configuration is passed. Nested YAML keys under config and secret are transformed one-to-one into n8n environment variables:
main:
config:
db:
type: postgresdb # becomes DB_TYPE=postgresdb
postgresdb:
host: postgres.internal # becomes DB_POSTGRESDB_HOST=postgres.internal
secret:
n8n:
encryption_key: from-a-secret # becomes N8N_ENCRYPTION_KEY
Once that mapping clicks, every n8n environment variable in the documentation is reachable from the chart without waiting for the chart to add explicit support for it.
Do not run production on the bundled SQLite
n8n ships with SQLite so that docker run works immediately. On Kubernetes that default is a trap: SQLite means a single writer, which means exactly one replica, which means the entire reason you are on Kubernetes is unavailable to you.
Set DB_TYPE=postgresdb and point it at a real Postgres instance before anything else. Not a Postgres pod with an emptyDir, not a sidecar — a managed instance or a properly operated StatefulSet with backups you have actually restored from once.
n8n’s database holds workflows, credentials and execution history. It is the state of your automation platform. Losing it loses everything except whatever workflow JSON someone happened to export.
Queue mode: what the extra pods buy
In the default single-process mode, one pod does everything: serves the editor, receives webhooks, and executes workflows. A long-running execution blocks the editor. A traffic spike on a webhook competes with a scheduled job.
Queue mode splits those responsibilities. Redis holds a job queue; the main pod serves the UI and enqueues; worker pods pull and execute; optional webhook pods handle inbound HTTP separately.
main:
config:
executions:
mode: queue
queue:
bull:
redis:
host: redis.internal
worker:
count: 3
webhook:
enabled: true
count: 2
The gain is real: workers scale horizontally with load, a slow workflow no longer blocks the editor, and webhook ingestion is isolated from execution. The cost is a Redis instance to operate, three deployment types to monitor, and a failure mode where workers are up, Redis is unreachable, and executions queue silently.
Queue mode is right for high, spiky volume. For a team running a few dozen workflows on a schedule, it is infrastructure you will maintain and never need.
The encryption key, and the mistake that eats credentials
n8n encrypts stored credentials with N8N_ENCRYPTION_KEY. If the chart generates one and you do not persist it, the next redeploy generates a different one and every stored credential in the database becomes undecryptable. The workflows remain; the credentials are gone.
Generate the key yourself, store it in a Kubernetes Secret you back up separately from the cluster, and reference it. Every pod — main, workers, webhooks — must have the same key, or workers cannot decrypt the credentials for jobs they pull.
This is the single most common way a self-hosted n8n installation loses data, and it usually happens during an otherwise routine upgrade.
Persistence, ingress and the rest of the checklist
Beyond the database, a few things need attention before this counts as running:
- Persistent volume for
/home/node/.n8n. Even with Postgres configured, some local state lives here. - Ingress and TLS. Webhooks need a public HTTPS URL, and
WEBHOOK_URLmust be set to the external address or n8n will generate webhook URLs pointing at the cluster-internal service name. - Resource requests and limits. Workflow executions are bursty; workers OOM-killed mid-execution leave jobs in an ambiguous state.
- Execution data pruning.
EXECUTIONS_DATA_PRUNEand a max age, or the executions table grows without limit until Postgres is the problem. - Timezone.
GENERIC_TIMEZONE, or every cron trigger fires on UTC while you reason in local time.
None of these is difficult. All of them are discovered in production if they are not done first.
Is Kubernetes the right place for this
The honest question. Kubernetes earns its complexity when you have a cluster already, a platform team who operates it, and n8n is one workload among many. In that setting the chart is a good way to run it and this is all routine.
If the cluster exists because of n8n, the arithmetic is worse. You have taken on a control plane, a Postgres instance, a Redis instance, ingress, certificate management and an upgrade cadence, to run a workflow tool. That is a real ongoing cost measured in someone’s attention, not just in compute.
Kubernetes is not something RunxBuild offers, and this post is not a pitch against it — for teams already on it, the chart is the right answer. But if the cluster is being stood up for this one workload, a managed n8n with a plan, a URL, environment variables in a dashboard and a managed Postgres beside it removes the operational surface entirely, and n8n on a $6 Basic plan with a database next to it covers a great deal of real usage.
How this fits the rest of the stack
The Helm chart is solid and queue mode genuinely solves the problems it claims to. The question is whether you need the topology or have inherited it — Redis, Postgres, three pod types and an encryption key with no recovery path is a lot of surface for a workflow tool serving one team. Before committing, it is worth pricing the managed alternative: the RunxBuild hosting calculator shows an n8n instance and a managed database as line items you can compare against what the cluster actually costs to run.
Useful related references:
- n8n vs Make: Where the Complexity Goes
- n8n Use Cases: What It Is Genuinely Good At, and What It Is Not
- n8n Alternatives: The Honest Comparison by What You Are Escaping
- Services on RunxBuild
FAQ
Is there an official n8n Helm chart?
The widely used chart is community-maintained rather than published by n8n, available on Artifact Hub and actively developed. It supports the full production topology including queue mode with separate worker and webhook deployments.
Do I need queue mode?
Only for high or spiky execution volume. Queue mode adds Redis, separate worker and webhook deployments, and more failure modes. A team running a few dozen scheduled workflows is well served by the single-process default.
Can I use the bundled SQLite on Kubernetes?
Not for anything real. SQLite allows a single writer, so you are locked to one replica and cannot scale or roll safely. Set DB_TYPE=postgresdb and point it at a properly backed-up Postgres instance.
What happens if I lose the n8n encryption key?
Every stored credential becomes undecryptable. Workflows survive, credentials do not, and they must all be re-entered. Generate the key yourself, keep it in a Secret backed up outside the cluster, and use the identical key across main, worker and webhook pods.
Why do my webhook URLs point to an internal address?
WEBHOOK_URL is not set to the external hostname. n8n generates webhook URLs from that variable, so without it you get the cluster-internal service name, which no external service can reach.