How n8n runs
The process that you started locally on the previous page ran all of n8n on its own. Production setups split n8n across many processes, and n8n Cloud runs the same code in thousands of customer instances. On this page, we add each part of the production setup and explain why it exists.
Week 1 follows your three steps from the previous page through this setup: the publication, the webhook call, and the message to the agent.
One process
pnpm start runs the CLI command n8n start. A process that runs this command is called a main. In your session, the main:
- served the editor: the web app, and the REST API under
/that the editor calls.rest - received the calls to
/andwebhook-test/ hello /, and your message to the agent.webhook/ hello - ran both workflow executions, and sent the progress of the manual execution to your browser tab via websocket.
- ran the agent turn, and streamed its answer back in the HTTP response of your message.
The inside of a main looks somewhat like most Express applications. Controllers take requests and call services. Services call repositories, and repositories use TypeORM. A small dependency injection container, @n8n/, creates the services, and decorators register the routes.
Each workflow execution is passed to the execution engine, a library in n8n-core that runs the nodes of a workflow and knows nothing about HTTP or the database. (This is the v1 engine. Engine v2 is in development, and its docs state the current design.)
Agent turns run on another library, the agent runtime in @n8n/. Workflow executions and agent turns share the same nodes, credentials, permissions, and database.
flowchart LR
E([Editor]) --> C
W([Webhook callers]) --> C
subgraph M [Main]
C[Controllers] --> S[Services]
S --> R[Repositories]
S --> EN[Execution engine]
S --> AR[Agent runtime]
end
R --> DB[(Database)]
Workers
In regular mode, one process serves the editor and runs executions, so heavy executions can slow the editor down. In queue mode (also called scaling mode), a main sets up the execution and adds a job to a Bull queue backed by Redis.
Alongside the main, processes that run the CLI command n8n worker are called workers. A worker takes the job from the queue and runs the execution. The job carries only the ID of the execution. The worker reads the workflow and the input from the database. When the execution ends, the worker saves the results to the database and reports completion to the main through the queue.
Processes that run the CLI command n8n webhook are called webhook processes. A webhook process only receives production webhook calls and adds their jobs to the queue. Busy instances run several of them behind a load balancer, to take in more webhook calls and keep that load off the main that serves the editor.
In queue mode, workers run only workflow executions, and agent turns still run on the main.
| Work | Regular mode: main |
Queue mode: main |
Queue mode: worker |
Queue mode: webhook process |
|---|---|---|---|---|
| Serve the editor and the APIs | yes | yes | no | no |
| Receive production webhooks | yes | yes | no | yes |
| Run workflow executions | yes | no | yes | no |
| Fire schedules and poll other services | yes | yes | no | no |
| Run agent turns | yes | yes | no | no |
Multi-main
With one main, a stopped main takes down the editor, the APIs, the schedules and polling triggers, and the agent turns. Multi-main runs several mains behind a load balancer for higher availability.
Several mains cause a new problem: some work must happen exactly once. If two mains ran the same poller, each new record would start two executions. Therefore one main is the leader, and only the leader runs pollers. Schedules need no leader, because any main starts each due run from a job in the database. The leader holds a key in Redis that expires after a few seconds and renews it while it runs. If the leader dies, another main takes the key.
Mains and workers broadcast changes over Redis pubsub. For example, if you publish a workflow through a main that is not the leader, that main broadcasts a command, and the leader starts the triggers.
In queue mode with multi-main, all the processes connect like this:
flowchart TB
E([Editor]) --> LB[Load balancer]
C([Webhook callers]) --> LB
LB --> M
LB --> WH[Webhook processes]
subgraph M [Mains]
direction LR
L[Leader]
O[Other mains]
end
subgraph R [Redis]
direction LR
Q[Queue]
P[Pubsub]
end
M --> Q
WH --> Q
M --- P
Q --> W[Workers]
WH --- P
P --- W
M --> DB[(Database)]
WH --> DB
W --> DB
n8n Cloud
n8n Cloud runs one instance for each customer. A control plane outside the n8n repository creates, configures, and upgrades each instance. It sets the environment variables of each instance, including N8N_DEPLOYMENT_TYPE=cloud. It also loads hooks into the process, which add the limits of each plan and usage reports.
The control plane depends on these names and files in the n8n repository, and no n8n test checks them:
- Environment variable names. To retire an old name, keep reading it in its
@Configclass for a release, and add a warning toDeprecationService. - Module names and license feature names.
- The external hooks, and the files and methods that they import, such as
HooksService. A moved file makes every n8n Cloud instance fail at startup. Search the code for "cloud hooks" before you move code. - The health endpoints
/andhealthz /, andhealthz/ readiness /.metrics - The commands
n8n export:entitiesandn8n import:entities. n8n Cloud uses them to copy whole tables out of an instance and back in.
Before you add a branch on N8N_DEPLOYMENT_TYPE, check if a license feature or a setting can do the same job. Then self-hosted users get the behavior too.
Licensing
Paid features ship in every instance, including self-hosted ones. A license decides if they run. See Licensing.
Compatibility
Upgrading an n8n instance must not change what a saved workflow does. Common ways to change behavior safely:
- In a node, add a new node version (
typeVersion). Saved workflows keep the old version. - In the engine, add a workflow setting. New workflows get the new behavior, and saved workflows keep the old one.
- For the whole instance, add an opt-in environment variable. Instances keep the old behavior until an admin turns it on.
- If no safe way exists, wait for the next major version to make a breaking change.
Packages
| Package | Holds |
|---|---|
packages/ |
CLI commands, HTTP server, controllers, and most services and modules: auth and SSO, credentials, executions and their lifecycle, triggers and webhooks, queue mode and pubsub, push, task runners, licensing, events and telemetry, public API, and more |
packages/ |
Execution engine, node execution contexts (the helpers that nodes call), trigger and poller runtime, node and credential loading, binary data storage, encryption, and instance settings |
packages/ |
Workflow model, expression evaluator, and shared types, used by both backend and frontend |
packages/ |
Entities, repositories, and migrations |
packages/ |
Agent runtime |
packages/ |
Backend of the n8n Assistant, the agent that builds and fixes workflows for the user |
packages/ |
Request and response types that the editor shares |
packages/ |
Config from env vars |
packages/ |
Modules in their own packages |
packages/packages/ |
Built-in nodes |
Quiz
- In queue mode, a production webhook call arrives on a main. Which process runs the execution?
In queue mode, a main does not run production executions. A worker takes the job from Redis and runs it.
- A worker finishes an execution. What does it do with the result?
The job carries only the ID of the execution, so the database holds the data.
- In multi-main, the leader dies. What happens to pollers?
The leader renews its key while it runs, so a dead leader loses the key within a few seconds.
- You rename an environment variable, and all tests pass. What can still break?
Environment variables are a contract with the n8n Cloud control plane outside the n8n repository. No test in the n8n repository checks it.
- You want to change what a node does. How do saved workflows keep their behavior?
A node stores its
typeVersion. A change of behavior goes into a new version.