Let’s be honest:
Most automation tools lock you in. Monthly fees that scale with usage. Data stuck in someone else’s cloud. Zero control over what happens under the hood.
n8n flips that script.
It’s a workflow automation platform that you can self-host (for free) or run in the cloud. You get 400+ integrations, full code access when you need it, and complete ownership of your data.
In this guide, you’ll learn everything about n8n: from “what is this thing” to running production workflows that handle thousands of executions daily.
No fluff. No theory dumps. Just what works.
n8n in 2 Minutes: What It Is and Why Teams Are Switching
n8n (pronounced “n-eight-n”) connects your apps and automates workflows. Like Zapier—but you own everything.
Who’s using n8n right now?
- Ops teams — killing manual copy-paste between tools
- Growth & marketing — syncing leads, triggering campaigns, enriching data
- Developers — building internal tools without spinning up a full backend
- Data teams — lightweight ETL without the Airflow complexity
Why teams switch from Zapier/Make
Three reasons keep coming up:
1. Cost gets real at scale
Zapier charges per “task.” Run 10,000 tasks/month? That’s $400+. On n8n self-hosted, same volume costs you ~$20 in server fees.
2. “I need to write actual code here”
Zapier’s code steps are sandboxed. n8n gives you full JavaScript/Python access. Need to call an internal API? Parse weird XML? Loop through 500 items? No problem.
3. Data can’t leave our servers
Healthcare, finance, legal—some industries can’t send data through third-party clouds. n8n self-hosted runs 100% on your infrastructure.
The trade-off: n8n has a learning curve. The UI is powerful but dense. Give yourself 2-3 hours to get comfortable. After that, you’ll wonder how you lived without it.
Real Use Cases (Steal These Ideas)
Here’s what teams actually build with n8n. Not theory—working automations you can replicate.
Notifications & Incident Response
Trigger: Error in your app, threshold crossed, or form submitted.
Flow: Slack alert → create Jira ticket → page on-call if critical.
Why n8n: Custom routing logic. “If P1, ping #incidents AND call PagerDuty. If P3, just log it.”
CRM & Sales Ops
Trigger: New lead in Typeform, HubSpot, or webhook.
Flow: Enrich with Clearbit → score → route to right sales rep → add to sequence.
Why n8n: Full control over lead scoring rules. No “upgrade to access this feature.”
E-commerce Automation
Trigger: New order, stock change, or abandoned cart.
Flow: Sync inventory to 3 channels → update prices → trigger fulfillment.
Why n8n: Handle thousands of SKU updates without per-task pricing killing you.
Data Sync & Mini-ETL
Trigger: Schedule (hourly/daily) or webhook.
Flow: Pull from API → transform → push to Google Sheets, Postgres, or warehouse.
Why n8n: Cleaner than scripts, simpler than Airflow, cheaper than Fivetran.
AI-Powered Workflows
Trigger: New email, support ticket, or document uploaded.
Flow: Send to OpenAI → classify/summarize → route or respond automatically.
Why n8n: Chain multiple AI calls, add human-in-the-loop, keep prompts versioned.
Pro tip: Start with ONE workflow. Get it running in production. Then expand. Most failed n8n projects try to automate everything at once.
Core Concepts (Know These Before Building)
Before you build your first workflow, nail these four concepts. Skip this section and you’ll waste hours debugging issues that have nothing to do with your logic.
Workflows, Nodes, Triggers, Executions
Workflow = your automation. A canvas where you connect nodes that do things.
Node = one step in your automation. Each node performs a single action: send an email, query a database, transform data, call an API.
Trigger = the node that starts your workflow. Two types:
- Webhook triggers wait for an incoming HTTP request (form submission, Stripe event, custom call)
- App triggers poll or listen to an app (new Gmail, new Slack message, new row in Airtable)
Execution = one run of your workflow from start to finish. n8n logs every execution so you can debug, replay, or audit later.
Mental model: Think of it like a recipe. The workflow is the recipe. Nodes are the steps. The trigger is what makes you start cooking (hunger, dinner party, etc.). Each time you cook = one execution.
Data Flow: Items, JSON, and Mapping
Here’s where n8n gets powerful—and where most beginners get stuck.
Everything in n8n is JSON. When a node runs, it outputs data as JSON objects. The next node receives that data and can use it.
Items = individual pieces of data flowing through your workflow. If you query a database and get 50 rows, you have 50 items. Each item passes through subsequent nodes.
Mapping = pulling data from previous nodes into the current one. Instead of hardcoding values, you reference them: {{ $json.email }} grabs the email field from the incoming data.
// Example: incoming data from a webhook
{
"name": "John",
"email": "john@example.com",
"company": "Acme Inc"
}
// Reference in next node
{{ $json.name }} → "John"
{{ $json.email }} → "john@example.com"The key insight: Data flows left-to-right. Each node transforms or routes items. If something’s wrong, check what data is actually arriving at each step (n8n shows this in the execution log).
Credentials: Connect Apps Without Exposing Secrets
Credentials store your API keys, OAuth tokens, and passwords. You create them once, then reuse across workflows.
Why this matters:
- Secrets are encrypted at rest
- You don’t copy-paste API keys into every workflow
- Changing a credential updates all workflows using it
- Team members can use credentials without seeing the actual values
Common credential types:
- API Key — simple key/secret pair
- OAuth2 — redirects to the app for authorization (Google, Slack, HubSpot)
- Basic Auth — username/password
- Header Auth — custom headers for APIs that don’t fit other patterns
Security note: On self-hosted n8n, credentials are encrypted with your
N8N_ENCRYPTION_KEY. Lose that key = lose access to all stored credentials. Back it up.
Environments: Dev vs Prod, Versions, Export/Import
n8n doesn’t have built-in environment separation. But you need it. Here’s how teams handle this:
Option 1: Separate instances
Run two n8n installations—one for development, one for production. Build and test in dev, then export the workflow JSON and import to prod.
Option 2: Workflow tags + naming conventions
Prefix workflow names: [DEV] Lead enrichment vs [PROD] Lead enrichment. Not ideal, but works for small teams.
Option 3: Git-based version control (recommended)
Export workflows as JSON, store in Git. Track changes, review before deploying, roll back if needed. This is how serious teams manage n8n at scale.
Export/Import workflow:
- In n8n, select workflow → Download → saves as
.json - Commit to Git with a descriptive message
- On prod instance: Import → upload the JSON
- Activate the workflow
Watch out for: Credentials don’t export. After importing a workflow, you’ll need to re-link credentials on the new instance.
Cloud vs Self-Hosted: Which One’s Right for You?
You’ve got two paths. Both work. The right choice depends on your constraints, not on what’s “better.”
Choose n8n Cloud if…
- You want to start today. Sign up, build, deploy. No server setup, no Docker, no maintenance.
- Your team isn’t technical. Cloud handles updates, backups, SSL, scaling. You focus on workflows.
- You need collaboration features. Multiple users, shared credentials, workflow permissions—built in.
- Budget is predictable. Pay per execution. Know your costs upfront.
Cloud makes sense for: marketing teams, small ops teams, agencies, anyone who values speed over control.
Choose Self-Hosted if…
- Data can’t leave your infrastructure. Healthcare, finance, legal—compliance often requires on-prem.
- You need internal network access. Connect to databases, APIs, or services that aren’t exposed to the internet.
- Volume is high and budget matters. At 50,000+ executions/month, self-hosting costs a fraction of Cloud.
- You want full control. Custom domains, your own backup strategy, specific n8n versions, no vendor dependency.
Self-hosted makes sense for: dev teams, companies with infra capabilities, regulated industries, high-volume use cases.
The Decision Checklist
Ask yourself these five questions:
| Question | Cloud | Self-Hosted |
|---|---|---|
| Do I have someone to manage a server? | No → Cloud | Yes → Either |
| Does data need to stay on my network? | No → Cloud | Yes → Self-host |
| Will I run 50k+ executions/month? | No → Cloud | Yes → Self-host |
| Do I need internal API/DB access? | No → Cloud | Yes → Self-host |
| Do I need to start in < 1 hour? | Yes → Cloud | No → Either |
Still unsure? Start with Cloud. You can always migrate to self-hosted later—workflows export as JSON, so nothing’s locked in.
Pricing reality check: Cloud’s free tier gives you 2,500 executions/month. Starter is
€20/month for 10k executions. Self-hosted costs whatever your server costs (€5-20/month on Hetzner, DigitalOcean, etc.) with unlimited executions.
Quick Installation (Recommended Paths)
Skip the 47-step tutorials. Here’s how to get n8n running in minutes.
Local Testing (Docker or npm)
Docker (recommended) — one command, done:
docker run -it --rm --name n8n -p 5678:5678 n8nio/n8nOpen http://localhost:5678. You’re in.
Data won’t persist after you stop the container. That’s fine for testing. For persistence, add a volume:
docker run -it --rm --name n8n -p 5678:5678 \
-v n8n_data:/home/node/.n8n \
n8nio/n8nnpm (if you don’t have Docker):
npx n8nRequires Node.js 18+. Same deal: http://localhost:5678.
Production Server with Docker Compose
For real deployments, use Docker Compose. This setup includes PostgreSQL (recommended over SQLite for production) and persistent storage.
Create a docker-compose.yml:
version: '3.8'
services:
n8n:
image: n8nio/n8n
restart: always
ports:
- "5678:5678"
environment:
- N8N_HOST=n8n.yourdomain.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.yourdomain.com/
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
postgres:
image: postgres:15
restart: always
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:Create a .env file (don’t commit this):
POSTGRES_PASSWORD=your-secure-password-here
N8N_ENCRYPTION_KEY=your-32-char-encryption-keyGenerate a proper encryption key:
openssl rand -hex 16Start everything:
docker compose up -dEssential Environment Variables
These are the variables that actually matter. Skip the rest until you need them.
| Variable | What it does | Example |
|---|---|---|
N8N_HOST | Your domain (required for webhooks) | n8n.yourdomain.com |
N8N_PROTOCOL | http or https | https |
WEBHOOK_URL | Full URL for incoming webhooks | https://n8n.yourdomain.com/ |
N8N_ENCRYPTION_KEY | Encrypts credentials. Back this up. | 32-char hex string |
N8N_BASIC_AUTH_ACTIVE | Enable login protection | true |
N8N_BASIC_AUTH_USER | Username | admin |
N8N_BASIC_AUTH_PASSWORD | Password | secure-password |
For reverse proxy (Nginx/Traefik): Make sure to forward the Host header and enable WebSocket proxying. n8n needs both for the editor to work properly.
Production checklist:
✅ PostgreSQL instead of SQLite
✅ Encryption key backed up securely
✅ HTTPS via reverse proxy
✅ Basic auth or SSO enabled
✅ Regular backups of database + n8n_data volume
Your First Workflow from A to Z
Time to build something real. We’ll create a webhook that receives form data, validates it, and sends a Slack notification. Classic pattern, infinite variations.
Example: Webhook → Process → Action
Step 1: Create a new workflow
Click “Add workflow” in n8n. Name it something useful: Contact Form → Slack.
Step 2: Add a Webhook trigger
- Click the
+button - Search for “Webhook”
- Select Webhook node
- Set HTTP Method to
POST - Copy the “Test URL” (you’ll need this)
Your webhook is now listening. It looks like:https://your-n8n.com/webhook-test/abc123
Step 3: Test with sample data
Send a test request (use curl, Postman, or your browser console):
curl -X POST https://your-n8n.com/webhook-test/abc123 \
-H "Content-Type: application/json" \
-d '{"name": "John", "email": "john@example.com", "message": "Hello!"}'Click “Execute workflow” in n8n. You should see the incoming data in the Webhook node output.
Step 4: Add validation (IF node)
- Add an IF node after the Webhook
- Condition:
{{ $json.email }}→ “is not empty” - This creates two branches: true (valid) and false (invalid)
Step 5: Send to Slack
- On the “true” branch, add a Slack node
- Connect your Slack credentials (OAuth2)
- Select channel, compose message:
New contact form submission!
Name: {{ $json.name }}
Email: {{ $json.email }}
Message: {{ $json.message }}Step 6: Activate
Toggle the workflow to “Active.” Your test URL becomes a production URL. Done.
The n8n Dev Loop: Test, Replay, Activate
This is how you’ll spend most of your time in n8n:
1. Build with test data
Use “Execute workflow” to run with sample data. Each node shows its input/output—click to inspect.
2. Pin data for iteration
Right-click a node → “Pin data.” Now that node always outputs the same data while you build downstream logic. Huge time saver.
3. Replay executions
Go to “Executions” tab. Click any past run to see exactly what happened. Click “Retry” to run it again with the same input.
4. Debug with execution log
Something broke? The execution log shows every node, its input, output, and any errors. No guessing.
5. Activate when ready
Only active workflows respond to triggers. Keep it inactive while building, activate when tested.
Pro tip: Use “Execute workflow” with the webhook node selected—n8n will wait for an incoming request, letting you test with real data from your actual form/app.
Best Practices: Naming, Folders, Comments
Your future self will thank you. So will your teammates.
Naming conventions:
Workflows:
[Team] Action - Source → Destination
Examples:[Sales] New Lead - Typeform → HubSpot,[Ops] Daily Report - DB → SlackNodes: Describe what they do, not what they are
❌IF,HTTP Request,Code
✅Check if email valid,Fetch user from API,Format message
Use folders:
Group workflows by team, project, or function. n8n supports folders—use them before you have 50 workflows in a flat list.
Add sticky notes:
The yellow sticky note node is documentation. Use it to explain:
- Why this workflow exists
- What triggers it
- Any gotchas or edge cases
- Who to contact if it breaks
Comment your code nodes:
If you’re writing JavaScript in a Code node, comment it. You’ll forget what it does in 3 months.
// Extract unique email domains from contact list
// Used for: lead segmentation by company
const domains = items.map(item => {
const email = item.json.email;
return email.split('@')[1];
});
return [...new Set(domains)].map(d => ({ json: { domain: d } }));Mastering Expressions (n8n’s Superpower)
Expressions are what turn n8n from “connect two apps” into “build anything.” Once you get this, you’ll automate things you didn’t think possible.
Syntax, Editor, Variables
Opening the expression editor:
Click any input field → click the fx button (or press /). You’re now in expression mode.
Basic syntax:
Everything inside {{ }} is evaluated as JavaScript.
{{ $json.email }} // Get email from current item
{{ $json.name.toUpperCase() }} // Transform to uppercase
{{ $json.price * 1.2 }} // Math operations
{{ $json.items.length }} // Array lengthKey variables you’ll use constantly:
| Variable | What it gives you |
|---|---|
$json | Current item’s data |
$input | All items from previous node |
$node["NodeName"] | Output from a specific node |
$workflow | Workflow metadata (id, name) |
$execution | Current execution info |
$now | Current timestamp (Luxon DateTime) |
$today | Today at midnight (Luxon DateTime) |
Accessing nested data:
{{ $json.user.address.city }} // Dot notation
{{ $json["field-with-dashes"] }} // Bracket notation for special chars
{{ $json.items[0].name }} // Array accessTournament Mode, Dates (Luxon), and JSON Queries (JMESPath)
Tournament mode explained:
When a node outputs multiple items, expressions run once per item. But what if you need data from item #3 while processing item #1?
That’s where $input.all() and $input.item come in:
{{ $input.all()[2].json.email }} // Get email from 3rd item
{{ $input.first().json.name }} // First item's name
{{ $input.last().json.id }} // Last item's id
{{ $input.item.json.email }} // Current item (same as $json)Dates with Luxon:
n8n uses Luxon for dates. Stop fighting with JavaScript Date objects.
{{ $now.toISO() }} // 2024-01-15T14:30:00.000Z
{{ $now.toFormat('yyyy-MM-dd') }} // 2024-01-15
{{ $now.minus({ days: 7 }).toISO() }} // 7 days ago
{{ $now.startOf('month').toISO() }} // First day of current month
{{ DateTime.fromISO($json.date).toFormat('dd/MM/yyyy') }} // Parse & formatCommon patterns:
$now.minus({ hours: 24 })— last 24 hours$today.startOf('week')— start of this week$now.diff($json.createdAt, 'days').days— days since creation
JMESPath for complex queries:
When you need to filter or transform arrays without Code nodes:
{{ $jmespath($json.users, "[?age > `30`].name") }} // Names of users over 30
{{ $jmespath($json.items, "[*].price | sum(@)") }} // Sum all prices
{{ $jmespath($json.data, "[?status == 'active']") }} // Filter active itemsPractical Patterns: Fallback, Safe Access, Formatting, Filtering
These patterns solve 90% of real-world expression problems.
Fallback values (handle missing data):
{{ $json.nickname || $json.name || "Anonymous" }}
{{ $json.phone ?? "No phone provided" }}Safe access (prevent crashes on undefined):
{{ $json.user?.address?.city || "Unknown" }} // Optional chaining
{{ $json.items?.[0]?.name }} // Safe array accessString formatting:
{{ $json.name.trim() }} // Remove whitespace
{{ $json.email.toLowerCase() }} // Lowercase
{{ $json.description.slice(0, 100) + "..." }} // Truncate
{{ $json.tags.join(", ") }} // Array to stringNumber formatting:
{{ $json.price.toFixed(2) }} // 2 decimal places
{{ Math.round($json.score) }} // Round
{{ ($json.amount / 100).toLocaleString('en-US', {style: 'currency', currency: 'USD'}) }}Conditional logic:
{{ $json.status === "active" ? "✅ Active" : "❌ Inactive" }}
{{ $json.score >= 80 ? "Pass" : "Fail" }}Quick filtering in expressions:
{{ $json.items.filter(i => i.price > 100) }} // Filter expensive items
{{ $json.users.find(u => u.role === "admin") }} // Find first admin
{{ $json.tags.includes("urgent") }} // Check if tag existsWhen to use Code node instead: If your expression is longer than one line, or you need loops with side effects, switch to a Code node. Expressions are for transformations, not business logic.
Reliability: Errors, Retries, Alerting
Your workflow runs perfectly. You deploy it. Day three—silence. You check: the API has been returning 500 for 72 hours. Nobody noticed.
This isn’t an edge case. This is the default if you don’t set up error handling.
Error Workflow: Centralize All Failures
n8n lets you create one Error Workflow that catches failures from all your other workflows. Set it up once, forget about individual error handling.
Setup (5 minutes):
- New workflow →
[System] Error Handler - Add an Error Trigger node (not Webhook)
- Connect to Slack/Email/DB
The Error Trigger receives everything you need:
{
"workflow": { "name": "Lead Sync to HubSpot" },
"execution": {
"url": "https://n8n.domain.com/execution/231",
"error": { "message": "Status 500", "node": "HTTP Request" }
}
}- In each important workflow’s Settings → Error Workflow → select your Handler
Slack template:
🚨 {{ $json.workflow.name }} — FAILED
Node: {{ $json.execution.error.node }}
{{ $json.execution.error.message }}
→ {{ $json.execution.url }}Every error, one place. No more surprises.
Stop And Error: Force a Failure
API returns 200, but the data is empty. n8n thinks the workflow “succeeded.” You know it didn’t.
Stop And Error node tells n8n: “This is an error. Mark as failed. Trigger the Error Workflow.”
IF node: $json.results.length === 0
↓ True
Stop And Error: "API returned 0 results — likely rate limited"When to use:
- API 200 + empty response
- Business rule violated (duplicate, missing field)
- Rate limit hit — you don’t want partial data
Strategies: Retry, Backoff, Idempotency
Retry on Fail
Every node → Settings → Retry on Fail.
| Setting | Recommendation |
|---|---|
| Wait | 1000–5000ms |
| Max Retries | 3 (more = needs intervention) |
Exponential Backoff
For APIs with rate limits—fixed wait doesn’t help. Increase exponentially:
const attempt = $json.attemptCount || 1;
const waitMs = Math.min(1000 * Math.pow(2, attempt), 30000);
// 1s → 2s → 4s → 8s → max 30sIdempotency
Retry = potential duplicate. Protect yourself:
// Generate unique key
const idempotencyKey = `${$json.email}-${$json.orderId}`;
// Check if exists before INSERT
// Or use UPSERT operationsDead-Letter Queue
Item fails 3+ times? Stop retrying. Log it for manual review:
IF: attemptCount > 3
→ True: Add to "Failed Items" sheet
→ False: Continue normallyReview weekly. Dead-letter items reveal systemic problems.
Proactive Monitoring
Don’t wait for failure. Alert on:
- Workflow hasn’t run in 24h (heartbeat check)
- Success rate < 90% for last 100 executions
- Execution time 2x above normal
Reality: Production problems are rarely crashes. They’re silent: empty responses, stopped webhooks, rate limits eating 30% of your data. Monitoring catches them. Hope doesn’t.
Security & Governance
n8n workflows often touch sensitive data: API keys, customer emails, payment info. A misconfigured instance is an open door.
This section isn’t optional. It’s the difference between “automation tool” and “security incident.”
The Basics: Lock It Down
HTTPS everywhere. No exceptions. Use a reverse proxy (Nginx, Traefik, Caddy) with Let’s Encrypt.
# Nginx minimal config
server {
listen 443 ssl;
server_name n8n.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:5678;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Authentication options:
| Method | When to Use | Setup Complexity |
|---|---|---|
| Basic Auth | Solo/small team, quick setup | Low |
| SSO (SAML/OIDC) | Enterprise, existing IdP | Medium |
| LDAP | Corporate environments | Medium |
Basic Auth env vars:
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=use-a-strong-password2FA: Available on n8n Cloud and Enterprise. For self-hosted Community, SSO with 2FA-enabled IdP is your path.
Reduce attack surface:
- Don’t expose n8n directly to internet. Use VPN or IP whitelist.
- Disable public API if you don’t need it:
N8N_PUBLIC_API_DISABLED=true - Run n8n as non-root user (Docker default does this)
- Limit outbound network if possible (firewall rules)
Patching: The Boring Part That Saves You
n8n has had critical vulnerabilities. Every automation platform has. The question is: how fast do you patch?
Real example: In early 2024, a critical RCE vulnerability (CVE-2024-xxxx) allowed authenticated users to execute arbitrary code. Fixed in hours, but instances that hadn’t updated were exposed.
Your patching routine:
- Subscribe to releases: Watch the n8n GitHub repo or follow @naborso
- Test before prod: Update staging first, verify workflows still work
- Automate updates: Use Watchtower for Docker or scheduled CI/CD
# Watchtower auto-updates (use with caution in prod)
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower n8n --interval 86400Rule of thumb: Security patches within 48h. Feature updates within 2 weeks.
Credentials & Secrets: Handle With Care
n8n encrypts credentials at rest using N8N_ENCRYPTION_KEY. This is non-negotiable.
If you lose this key, you lose all stored credentials. No recovery. Backup it separately from your database.
Best practices:
# Generate a strong key
openssl rand -hex 32
# Store it outside your repo
# Use environment variables, not config files
N8N_ENCRYPTION_KEY=your-64-char-hex-keyCredential rotation:
Most teams forget this. APIs get compromised. Employees leave. Rotate credentials:
- Quarterly: High-risk credentials (payment APIs, admin tokens)
- Annually: Lower-risk credentials (analytics, newsletters)
- Immediately: When employee with access leaves
RBAC (Role-Based Access Control):
Available on n8n Cloud Team/Enterprise and self-hosted Enterprise.
| Role | Can Do |
|---|---|
| Owner | Everything |
| Admin | Manage users, all workflows |
| Member | Own workflows, shared workflows |
| Viewer | Read-only (audit, reporting) |
For Community self-hosted: one instance = one user level. Separate instances for different access levels if needed.
Audit trail: Enterprise plans log who did what. For Community, enable execution logging and monitor access logs from your reverse proxy. Not perfect, but better than nothing.
Production: Performance, Observability, Scaling
Your n8n instance works great with 100 executions/day. Then you hit 10,000. Suddenly workflows timeout, the UI crawls, and you’re debugging at 2am.
Scale before you need to. Here’s how.
Performance: Where It Breaks First
Database is usually the bottleneck. SQLite works for testing. PostgreSQL is mandatory for production.
# Switch to Postgres (docker-compose.yml)
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_DATABASE=n8nExecution data piles up. By default, n8n keeps all execution history. At scale, this kills performance.
# Prune old executions
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168 # hours (7 days)
EXECUTIONS_DATA_SAVE_ON_ERROR=all
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none # aggressive, but fastMemory matters. Default Node.js memory limit is ~1.5GB. Heavy workflows need more:
NODE_OPTIONS=--max-old-space-size=4096 # 4GBQuick wins:
| Problem | Fix |
|---|---|
| Slow UI | Prune executions, add PostgreSQL indexes |
| Workflow timeouts | Increase EXECUTIONS_TIMEOUT (default 3600s) |
| Webhook delays | Use queue mode (see Scaling below) |
| Memory spikes | Split large workflows, process in batches |
Observability: Know Before It Breaks
Execution logs are your source of truth. n8n stores every run with input/output data. Use it.
- Success rate trending down? API changed, credentials expired, or rate limit hit.
- Execution time increasing? Upstream service degrading or data volume growing.
- Specific node failing? Usually credentials or API format change.
External monitoring setup:
- Health endpoint:
GET /healthzreturns 200 if n8n is up - Uptime monitoring: Point Uptime Robot, Pingdom, or Better Stack at it
- Alerting: Connect your Error Workflow to PagerDuty/Opsgenie for critical workflows
Metrics to track:
# Enable Prometheus metrics (self-hosted)
N8N_METRICS=true
N8N_METRICS_PREFIX=n8n_
# Scrape from /metrics endpointKey metrics:
n8n_workflow_executions_total— execution count by statusn8n_workflow_execution_duration— how long workflows taken8n_api_requests_total— API load
Scaling: When One Instance Isn’t Enough
Queue mode is the first step. Instead of executing workflows immediately, n8n pushes jobs to a queue. Separate workers process them.
# Main instance (receives webhooks, queues jobs)
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
# Worker instance(s) (processes jobs)
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
N8N_DISABLE_UI=true # workers don't need UIWhen to use queue mode:
- Webhook response time matters (queue mode responds instantly)
- You need horizontal scaling (add workers, not bigger servers)
- Workflows are CPU/memory intensive
Scaling strategy by volume:
| Executions/day | Setup |
|---|---|
| < 1,000 | Single instance, PostgreSQL |
| 1,000–10,000 | Queue mode + 2-3 workers |
| 10,000–100,000 | Queue mode + auto-scaling workers + Redis cluster |
| 100,000+ | Contact n8n Enterprise or architect custom solution |
Backups (don’t skip this):
# PostgreSQL daily backup
pg_dump -U n8n n8n > backup_$(date +%Y%m%d).sql
# n8n data volume (credentials, etc.)
docker run --rm -v n8n_data:/data -v $(pwd):/backup \
alpine tar czf /backup/n8n_data_$(date +%Y%m%d).tar.gz /dataAutomate this. Test restores quarterly. The backup you never tested is the backup that won’t work.
Reality check: Most teams don’t need queue mode until 5,000+ executions/day. Start simple. Add complexity when metrics demand it, not before.
License: Is n8n Really “Open Source”?
Short answer: No. But it’s close enough for most use cases.
n8n uses a Sustainable Use License (previously called “fair-code”). The source code is public on GitHub. You can read it, modify it, self-host it. But there are restrictions.
What You CAN Do
✅ Self-host for your own business — Run n8n internally, automate your processes, no fees, no limits.
✅ Modify the code — Fork it, customize nodes, build internal features. Your modifications stay yours.
✅ Use commercially — Your company can use n8n to make money. Automating sales, ops, marketing? All good.
✅ Contribute back — Submit PRs, report bugs, improve the platform. Community contributions are welcome.
What You CAN’T Do
❌ Resell n8n — You can’t package n8n and sell it as your own product.
❌ Offer n8n as a service — Hosting n8n for other companies (like your own “n8n Cloud”) requires a commercial license from n8n GmbH.
❌ Remove license headers — The attribution must stay in the code.
Why This Matters
If you’re a company using n8n internally: you’re fine. Self-host, customize, scale. No licensing fees.
If you’re an agency building automations for clients: also fine. You’re using n8n to deliver services, not reselling the software itself.
If you’re thinking of building a product on top of n8n (SaaS, managed hosting): talk to n8n first. You’ll need a commercial agreement.
The “Fair-Code” Philosophy
n8n chose this model to stay sustainable. Pure open source projects often struggle with funding—companies use the software for free while a small team maintains it for nothing.
Sustainable Use License = source available + commercial restrictions on competing with n8n directly.
Whether you agree with this model or not, understand it before you build. The license is clear, and n8n has enforced it.
Bottom line: For 95% of users—internal automation, agencies, startups—the license changes nothing. Self-host freely. Just don’t try to become the next n8n Cloud without a conversation first.
Pricing: How to Estimate Cost (No Surprises)
n8n pricing confuses people. Cloud charges per execution. Self-hosted is “free” but costs server time. Let’s break it down.
n8n Cloud Pricing
| Plan | Price | Executions | Best For |
|---|---|---|---|
| Free | €0 | 2,500/month | Testing, personal projects |
| Starter | €20/mo | 2,500 + €0.0035/extra | Small teams, low volume |
| Pro | €50/mo | 10,000 + €0.0020/extra | Growing teams |
| Enterprise | Custom | Unlimited | Large orgs, compliance needs |
What counts as an “execution”?
One workflow run = one execution. If your workflow processes 100 items, that’s still 1 execution. Sub-workflows count separately.
Estimate your monthly cost:
Monthly executions × Overage rate + Base price = Total
Example: 25,000 executions on Pro plan
10,000 included + (15,000 × €0.002) = €50 + €30 = €80/monthSelf-Hosted: The “Free” Option
No license fees. You pay for infrastructure:
| Provider | Spec | Monthly Cost |
|---|---|---|
| Hetzner CX21 | 2 vCPU, 4GB RAM | ~€6 |
| DigitalOcean | 2 vCPU, 4GB RAM | ~$24 |
| AWS t3.medium | 2 vCPU, 4GB RAM | ~$30 |
| Your own server | Varies | Electricity + time |
Add PostgreSQL (required for production): +€5-15/month managed, or run it yourself.
Real cost comparison at 50,000 executions/month:
| Option | Monthly Cost |
|---|---|
| n8n Cloud Pro | €50 + (40k × €0.002) = €130 |
| Self-hosted (Hetzner) | €6 server + €5 DB = €11 |
| Self-hosted (DigitalOcean) | $24 + $15 DB = ~€35 |
Self-hosted wins on cost. Cloud wins on time. Your DevOps hours have a price too.
When to Upgrade (Decision Points)
Free → Starter: You need more than 2,500 executions or multiple active workflows.
Starter → Pro: Overages are eating your budget. At ~5,000 executions, Pro becomes cheaper.
Pro → Enterprise: You need SSO, audit logs, priority support, or your legal team requires a signed contract.
Cloud → Self-hosted:
- You’re spending €100+/month on Cloud
- You have DevOps capacity
- Data residency matters
Hidden Costs to Watch
Cloud:
- Overages sneak up. Set billing alerts.
- Annual billing saves ~20%, but locks you in.
Self-hosted:
- Server maintenance time (updates, backups, debugging)
- Monitoring tools (Grafana, alerts)
- Your time when it breaks at 2am
My take: Start with Cloud Free or Starter. Get your workflows working. Once you’re at €100+/month and have someone who can manage infrastructure, consider self-hosting. The math only works if you actually maintain it.
Alternatives to n8n (And When They Win)
n8n isn’t always the answer. Here’s an honest look at when competitors make more sense.
Quick Comparison
| Tool | Best For | Pricing Model | Self-Host |
|---|---|---|---|
| n8n | Technical teams, high volume, data control | Free self-hosted / Cloud per-execution | ✅ Yes |
| Zapier | Non-technical users, quick setup | Per-task (expensive at scale) | ❌ No |
| Make | Visual builders, mid-complexity | Per-operation (cheaper than Zapier) | ❌ No |
| Pipedream | Developers, code-first | Generous free tier, per-credit | ❌ No |
| Airflow | Data engineering, DAGs | Free (self-managed) | ✅ Yes |
When Zapier Wins
Choose Zapier if:
- Your team isn’t technical and won’t become technical
- You need something working in 15 minutes
- Volume stays under 1,000 tasks/month
- Budget isn’t the constraint
Zapier’s UI is unmatched for simplicity. 5,000+ integrations. Zero learning curve. You pay for that convenience.
When Make Wins
Choose Make if:
- You want visual building but more power than Zapier
- Budget matters (Make is 4-5x cheaper per operation)
- You need branching, iterations, error handling
- Team can handle slightly more complexity
Make hits a sweet spot: more capable than Zapier, friendlier than n8n, reasonable pricing.
When Pipedream Wins
Choose Pipedream if:
- You’re a developer who thinks in code
- You want Node.js/Python with minimal abstraction
- Generous free tier matters (10,000 credits/month)
- You don’t need self-hosting
Pipedream is n8n’s closest competitor for technical users. Better DX for pure coders. But no self-hosting option.
When Airflow/Prefect Win
Choose Airflow or Prefect if:
- You’re building data pipelines, not app integrations
- Workflows are DAGs with complex dependencies
- Your team already knows Python
- You need serious scheduling and orchestration
These aren’t n8n competitors—they’re different tools. Airflow for data engineering. n8n for operational automation.
The Decision Framework
Ask yourself:
Who will build and maintain this?
- Non-technical → Zapier or Make
- Technical but not DevOps → n8n Cloud or Pipedream
- Full DevOps capability → n8n self-hosted or Airflow
What’s your volume?
- < 1,000/month → Anything works, pick easiest
- 1,000–50,000/month → Make or n8n Cloud
- 50,000+/month → n8n self-hosted
Where must data live?
- Anywhere → Cloud options are fine
- Your infrastructure only → n8n or Airflow
Honest take: Most teams should start with Make or Zapier. Graduate to n8n when you hit limits—either cost, complexity, or control. Starting with n8n “because it’s free” often means workflows that never get finished.
Conclusion + Next Steps
You’ve read 5,000+ words about n8n. Now what?
Your Action Plan (This Week)
Day 1: Get it running
- Cloud: Sign up free → build in browser
- Self-hosted:
docker run -p 5678:5678 n8nio/n8n→ localhost:5678
Day 2-3: Build your first real workflow
- Pick ONE repetitive task you do weekly
- Build the workflow (webhook → logic → action)
- Test with real data, not samples
Day 4-5: Make it production-ready
- Set up Error Workflow (centralized alerting)
- Enable Retry on Fail for API nodes
- Add credentials properly (not hardcoded)
Week 2: Scale what works
- Document your workflow (sticky notes)
- Add monitoring (execution success rate)
- Build workflow #2
Key Takeaways
n8n = power + ownership. You trade simplicity for control. Worth it at scale.
Start with Cloud. Graduate to self-hosted when you hit €100/month or need data control.
Error handling isn’t optional. One Error Workflow catches everything. Set it up day one.
The license is fine for 95% of users. Internal automation, agencies, startups—all good.
Alternatives exist for a reason. Non-technical team? Start with Make or Zapier. Come back when you outgrow them.
Official Resources
- n8n Documentation — The source of truth
- Workflow Templates — 900+ ready-to-use workflows
- Community Forum — Active, helpful community
- n8n GitHub — Source code, issues, releases
Need Help?
Building complex automations? Migrating from another platform? Not sure where to start?
We build n8n workflows for businesses. From simple integrations to enterprise deployments.
This guide is updated regularly. Last update: January 2026. Found an error or have suggestions? Let us know.
