When my Zapier bill hit $299/month, I started paying attention.
I had 47 active Zaps. Most were simple: form submission → CRM, daily report → email, new email → Slack. But Zapier's task-based billing means every action in every Zap costs a task. A 5-step Zap costs 5 tasks. At scale, it adds up fast.
I migrated everything to n8n (self-hosted) over three weekends. My automation cost dropped to $0. Here's the complete guide so you can do the same — with real workflow examples you can import directly.
Why People Switch from Zapier to n8n
The cost math. Zapier Professional: $49/month for 2,000 tasks. Zapier Team: $399/month for 50,000 tasks. A 5-step workflow that fires 100x/day = 500 tasks/day = 15,000 tasks/month. You'll need the Team plan just for that one workflow.
n8n self-hosted: free forever. n8n Cloud: $24/month with 2,500 executions and unlimited steps per execution. No task counting.
No execution limits when self-hosted. Run 1,000 workflows per minute — n8n doesn't count or throttle.
Code execution everywhere. The n8n Code node runs JavaScript or Python inline. No Zapier Formatter workarounds. No "Code by Zapier" add-on. Just write the logic.
Complex branching. Zapier Paths supports basic if/else. n8n has multi-level IF/Switch nodes, merge nodes, sub-workflows, loops, and full parallel branches.
Privacy. Self-hosted n8n means your data never touches a third-party server. For financial, HR, or customer data, this matters.
Concept Mapping: Zapier → n8n
| Zapier | n8n Equivalent |
|---|---|
| Zap | Workflow |
| Trigger | Trigger node (first node in workflow) |
| Action | Node |
| Filter | IF node |
| Paths | IF/Switch with multiple branches |
| Formatter | Code node (Set node for simple transforms) |
| Delay | Wait node |
| Task | Execution step (no billing in self-hosted) |
| Premium app | Most apps are free in n8n |
| Zapier Tables | External: Airtable, Notion, Google Sheets |
The mental model is the same: trigger → actions. n8n just has more nodes and fewer restrictions.
Migrating 3 Common Zapier Workflows
Workflow 1: Gmail → Slack Notification (Basic)
The Zapier version:
- Trigger: New email in Gmail matching label "Important"
- Action: Post message to Slack channel
n8n equivalent (import-ready JSON):
{
"name": "Gmail to Slack",
"nodes": [
{
"parameters": {
"pollTimes": { "item": [{ "mode": "everyMinute" }] },
"filters": { "labelIds": ["IMPORTANT"] }
},
"name": "Gmail Trigger",
"type": "n8n-nodes-base.gmailTrigger",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"operation": "postMessage",
"channel": "#notifications",
"text": "=:email: New important email\nFrom: {{$json[\"from\"]}}\n{{$json[\"snippet\"]}}"
},
"name": "Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [480, 300]
}
],
"connections": {
"Gmail Trigger": { "main": [[{ "node": "Slack", "type": "main", "index": 0 }]] }
}
}
Key differences:
- Gmail OAuth setup: same process as Zapier, done once in n8n's Credentials tab
- Polling every minute by default — or use Gmail push notifications for real-time
- Zero cost per execution regardless of frequency
Workflow 2: Form Submission → CRM + Welcome Email (Medium)
The Zapier version:
- Trigger: New Typeform response
- Action: Create HubSpot contact
- Action: Send welcome email via Gmail
n8n equivalent (import-ready JSON):
{
"name": "Typeform to HubSpot + Email",
"nodes": [
{
"parameters": { "formId": "YOUR_FORM_ID" },
"name": "Typeform Trigger",
"type": "n8n-nodes-base.typeformTrigger",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"resource": "contact",
"operation": "create",
"additionalFields": {
"email": "={{$json[\"answers\"][0][\"email\"]}}",
"firstname": "={{$json[\"answers\"][1][\"text\"]}}"
}
},
"name": "HubSpot",
"type": "n8n-nodes-base.hubspot",
"typeVersion": 2,
"position": [480, 300]
},
{
"parameters": {
"operation": "send",
"toList": "={{$node[\"HubSpot\"].json[\"email\"]}}",
"subject": "Welcome!",
"message": "=Hi {{$node[\"HubSpot\"].json[\"firstname\"]}}, thanks for signing up!"
},
"name": "Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [720, 300]
}
],
"connections": {
"Typeform Trigger": { "main": [[{ "node": "HubSpot", "type": "main", "index": 0 }]] },
"HubSpot": { "main": [[{ "node": "Gmail", "type": "main", "index": 0 }]] }
}
}
Key differences:
- Typeform → n8n uses a webhook (real-time push, not polling). No 15-minute delay
- In Zapier this costs 3 tasks per submission. In n8n self-hosted: zero
- Expression syntax
={{$json["field"]}}replaces Zapier's drag-to-map UI
Workflow 3: Scheduled Google Sheets Report (Advanced)
The Zapier version:
- Trigger: Schedule (daily 8 AM)
- Action: Google Sheets multi-row lookup
- Action: Formatter (math + text)
- Action: Send email report
n8n equivalent (import-ready JSON):
{
"name": "Daily Sheets Report",
"nodes": [
{
"parameters": {
"rule": { "interval": [{ "field": "cronExpression", "expression": "0 8 * * *" }] }
},
"name": "Schedule",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"operation": "getAll",
"documentId": { "value": "YOUR_SHEET_ID" },
"sheetName": { "value": "Sheet1" },
"returnAll": true
},
"name": "Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [480, 300]
},
{
"parameters": {
"jsCode": "const rows = items.map(i => i.json);\nconst today = new Date().toISOString().split('T')[0];\nconst todayRows = rows.filter(r => r.date === today);\nconst total = todayRows.reduce((sum, r) => sum + Number(r.amount || 0), 0);\nconst avg = todayRows.length > 0 ? (total / todayRows.length).toFixed(2) : 0;\nreturn [{ json: { total: total.toFixed(2), count: todayRows.length, avg, date: today } }];"
},
"name": "Code",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [720, 300]
},
{
"parameters": {
"operation": "send",
"toList": "you@company.com",
"subject": "=Daily Report — {{$json[\"date\"]}}",
"message": "=Summary:\n\nTotal: ${{$json[\"total\"]}}\nTransactions: {{$json[\"count\"]}}\nAverage: ${{$json[\"avg\"]}}"
},
"name": "Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [960, 300]
}
],
"connections": {
"Schedule": { "main": [[{ "node": "Google Sheets", "type": "main", "index": 0 }]] },
"Google Sheets": { "main": [[{ "node": "Code", "type": "main", "index": 0 }]] },
"Code": { "main": [[{ "node": "Gmail", "type": "main", "index": 0 }]] }
}
}
Key differences:
- The Code node replaces Zapier Formatter entirely — far more powerful (full JS, array math, conditionals)
- Zapier counts 4 tasks per daily run. n8n: zero
-
$json["field"]expressions give you full JavaScript power inline
What's Harder in n8n (Honest Assessment)
Initial credential setup. Zapier holds your hand through OAuth flows step by step. n8n requires creating credentials in the Credentials panel first, then assigning them to nodes. First-time users spend 20-30 minutes on this. After setup, credentials are saved and reused forever.
No guided app selection. Zapier's "Choose app and event" UI is beginner-friendly. n8n's node search is powerful but assumes you know what you're looking for. Spend 10 minutes browsing the node library first.
Expression syntax learning curve. ={{$json["field_name"]}} takes getting used to. Zapier's drag-to-insert mapping is more intuitive initially. n8n expressions are more powerful once learned — you can write any JS inline.
Self-hosting overhead. You need a server or use n8n Cloud. A $5-6/month VPS (Hetzner, DigitalOcean) runs n8n comfortably for most teams. Docker install: about 15 minutes.
Fewer out-of-box integrations. Zapier: 6,000+ apps. n8n: 400+ native integrations plus HTTP Request for any REST API. Covers ~95% of real use cases.
What's Better in n8n
- Unlimited executions (self-hosted) — run every minute, all day, zero throttling
- Code node — JavaScript and Python inline, no add-on needed, no tier gate
- Error handling built-in — Error Trigger node catches failures and alerts you
- Sub-workflows — call one workflow from another like a reusable function
- Export all workflows as JSON — no vendor lock-in
- Self-hosting privacy — your data never leaves your server
- Active community — n8n forum has detailed answers for most integration questions
Migration Checklist
Before you start:
- [ ] List all active Zaps and their task counts (Zapier dashboard → Usage)
- [ ] Mark business-critical Zaps (migrate these last)
- [ ] Install n8n:
docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n— or use n8n.io/cloud - [ ] Create credentials in n8n: Google OAuth, Slack, HubSpot, etc.
For each Zap:
- [ ] Map trigger to n8n trigger node
- [ ] Map each action to an n8n node
- [ ] Replace Formatter steps with Code or Set nodes
- [ ] Test with real data via n8n's built-in test runner
- [ ] Run both Zapier and n8n versions in parallel for 24-48h
- [ ] Deactivate the Zap once n8n version is confirmed working
After migration:
- [ ] Cancel or downgrade Zapier plan
- [ ] Add an Error Trigger node → Gmail to catch any n8n failures
- [ ] Bookmark n8n expression docs: docs.n8n.io/code/expressions/
Want Pre-Built Migrations?
If you'd rather import working workflows than build from scratch, FlowKit has 15 ready-to-use n8n automation templates — all under $30.
Most popular for Zapier migrants:
- Email Auto-Responder ($15) — keyword-triggered Gmail replies with Google Sheets routing
- Lead Capture to CRM ($19) — webhook → score → CRM → Slack → email drip
- Invoice Generator ($19) — monthly schedule → Sheets → HTML invoice → Gmail
All include full JSON you can import in one click, plus setup docs that work on both n8n self-hosted and n8n Cloud.
Migration is a weekend project, not a month-long initiative. Start with your three most-used Zaps, spend an hour with the expression syntax docs, and you'll wonder why you waited.













