n8n is great until it isn't. You hit a point where the visual canvas gets unwieldy, error handling is a nightmare of nested if-else nodes, and every complex workflow turns into a wall of spaghetti that only the person who built it can understand. If you've been there — staring at a 40-node workflow wondering why it broke at 2 AM — you already know the feeling.
Trigger.dev solves this by moving your automations into TypeScript code. Real code, real version control, real debugging. But the migration sounds painful. Rebuilding every workflow from scratch? Mapping every node to its code equivalent? Nobody has time for that.
Here's the shortcut we discovered: you can export your n8n workflow JSON, paste it into Claude Code, and have it generate the entire Trigger.dev equivalent — ready to deploy. No manual rewrite. No node-by-node translation. Just copy, paste, and hook it up.
Quick Answer
You can migrate from n8n to Trigger.dev by exporting your n8n workflow as JSON, pasting it into Claude Code, and asking it to generate the equivalent Trigger.dev task in TypeScript. Claude reads the n8n JSON, understands every node (triggers, HTTP requests, conditionals, data transformations), and produces clean, deployable Trigger.dev code. You then connect your credentials, deploy, and your workflow runs as code — with real version control, proper error handling, and none of the visual-canvas limitations that made you want to leave n8n in the first place.
Why We Started Moving Workflows Off n8n
We're not n8n haters. We still use it as a trigger and orchestration layer for plenty of client workflows. But for complex, multi-step automations that need reliability at scale, we kept hitting the same walls:
1. Debugging is painful. When a 30-node workflow fails on node 22, you're clicking through execution logs one node at a time. There's no stack trace, no breakpoints, no way to reproduce the exact failure locally.
2. Version control doesn't exist. You can export JSON and track it in Git, but there's no real diff experience. You can't review changes the way you review a pull request. When something breaks after a change, good luck figuring out what actually changed.
3. Error handling is bolted on. Every try-catch becomes an "Error Trigger" node connected to a separate branch. Complex error recovery turns into a parallel workflow that's harder to follow than the happy path.
4. Code logic in nodes is awkward. The moment you need a Function node with 50+ lines of JavaScript, you're writing code inside a JSON text field with no syntax highlighting, no type safety, and no imports. At that point, why not just write code?
5. Scaling gets expensive. n8n Cloud pricing scales with executions. Once you're running thousands of workflows per day, the cost adds up fast — and self-hosting n8n means managing infrastructure.
Trigger.dev eliminates all of these. Your workflows are TypeScript files. They live in your repo. You debug them like any other code. You deploy them to serverless infrastructure that scales to zero when idle and spins up instantly when triggered.
What Is Trigger.dev?
Trigger.dev is an open-source background job and workflow engine for TypeScript. Think of it as what n8n would be if it were built for developers instead of no-code users.
Key differences from n8n:
| Feature | n8n | Trigger.dev |
|---|---|---|
| Interface | Visual canvas | TypeScript code |
| Version control | Export JSON manually | Native Git |
| Error handling | Error Trigger nodes | try/catch + retries |
| Debugging | Click through execution logs | Console logs, breakpoints, local dev |
| Scaling | Per-execution pricing or self-host | Serverless, scales to zero |
| Testing | Manual re-runs | Unit tests, local dev server |
| Dependencies | Built-in node library | Any npm package |
| Scheduling | Cron node | Cron triggers in code |
| Webhooks | Webhook node | HTTP endpoint triggers |
The real power is that you can use any npm package, any API client, any library — without being limited to what n8n has a node for. Need to call a niche API? Just import their SDK. Need complex data transformation? Use lodash, date-fns, whatever you want.
The Migration Shortcut: n8n JSON → Claude Code → Trigger.dev
Here's the process we use with clients. It takes minutes, not days.
Step 1: Export Your n8n Workflow
In n8n, open the workflow you want to migrate. Click the three dots menu → Download. You'll get a .json file that contains every node, connection, credential reference, and configuration.
The JSON looks something like this (simplified):
{
"nodes": [
{
"type": "n8n-nodes-base.webhook",
"name": "Webhook",
"parameters": {
"httpMethod": "POST",
"path": "new-lead"
}
},
{
"type": "n8n-nodes-base.httpRequest",
"name": "Enrich Lead",
"parameters": {
"url": "https://api.apollo.io/v1/people/match",
"method": "POST",
"body": "{{ JSON.stringify({ email: $json.email }) }}"
}
},
{
"type": "n8n-nodes-base.if",
"name": "Check Score",
"parameters": {
"conditions": {
"number": [{ "value1": "={{ $json.score }}", "operation": "larger", "value2": 70 }]
}
}
}
],
"connections": { ... }
}
Step 2: Paste It Into Claude Code
Open Claude Code in your terminal (or VS Code extension) and give it a prompt like:
"Here's an n8n workflow JSON. Convert this to a Trigger.dev v3 task. Use the task pattern with proper error handling, retries, and logging. Keep the same logic and API calls."
Then paste the entire JSON.
Claude Code reads the full workflow structure — every node type, every connection, every conditional branch — and generates the equivalent TypeScript. It understands n8n's node types (Webhook, HTTP Request, If, Switch, Set, Function, Merge, etc.) and maps them to their code equivalents.
Step 3: Review the Output
Claude Code produces something like this:
import { task, logger } from "@trigger.dev/sdk/v3";
export const processNewLead = task({
id: "process-new-lead",
retry: { maxAttempts: 3 },
run: async (payload: { email: string; name: string }) => {
logger.info("New lead received", { email: payload.email });
// Enrich lead via Apollo
const enrichResponse = await fetch("https://api.apollo.io/v1/people/match", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.APOLLO_API_KEY!,
},
body: JSON.stringify({ email: payload.email }),
});
const enrichData = await enrichResponse.json();
// Score check — route based on lead quality
if (enrichData.score > 70) {
logger.info("High-value lead", { score: enrichData.score });
// Create deal in CRM
await fetch("https://api.hubspot.com/crm/v3/objects/deals", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
properties: {
dealname: `${payload.name} — Inbound`,
pipeline: "default",
dealstage: "qualifiedtobuy",
},
}),
});
// Notify sales team
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: "POST",
body: JSON.stringify({
text: `🔥 High-value lead: ${payload.name} (${payload.email}) — Score: ${enrichData.score}`,
}),
});
} else {
logger.info("Nurture sequence", { score: enrichData.score });
// Add to nurture campaign instead
// ... email sequence logic
}
return { processed: true, score: enrichData.score };
},
});
Clean. Readable. Debuggable. Version-controlled.
Step 4: Hook It Up
The code Claude generates uses environment variables for credentials (process.env.APOLLO_API_KEY, process.env.HUBSPOT_TOKEN, etc.). You add these to your Trigger.dev project, deploy, and the workflow is live.
For webhook triggers, Trigger.dev gives you an HTTP endpoint out of the box. Point your form, CRM, or webhook source to the new URL and you're done.
The entire process — export, paste, review, deploy — takes 15 to 30 minutes for a typical workflow. Compare that to manually rewriting it, which could take days.
What Claude Code Actually Understands
This isn't a dumb find-and-replace. Claude Code genuinely understands n8n's workflow structure:
- Node types: Webhook, HTTP Request, Function, If/Switch, Set, Merge, Split In Batches, Wait, Send Email, Slack, and dozens more
- Data flow: How n8n passes
$json,$node, and$itemsbetween nodes — Claude maps these to function parameters and return values - Expressions: n8n's
{{ }}expression syntax gets converted to template literals and proper variable references - Branching: If/Switch nodes become if/else or switch statements with the correct conditions
- Error handling: Error Trigger nodes become try/catch blocks with proper retry configuration
- Loops: Split In Batches and Loop nodes become
forloops or.map()calls - Credentials: Node credentials become
process.envreferences with the right naming
For complex workflows with 20+ nodes, Claude Code handles the full graph — following connections, respecting execution order, and maintaining data dependencies between steps.
Real Example: Client Invoice Processing Pipeline
Here's a real migration we did for a client. Their n8n workflow:
- Webhook receives invoice PDF URL from their intake form
- Download the PDF
- Send to an OCR service to extract text
- AI node extracts vendor name, amount, line items, and due date
- If amount > $5,000, flag for manual approval
- Otherwise, create entry in QuickBooks
- Notify the finance team in Slack
- Log everything to Airtable
The n8n workflow was 14 nodes with 3 error branches. We exported the JSON, pasted it into Claude Code, and got a single Trigger.dev task file — about 120 lines of TypeScript. The code was cleaner, the error handling was unified in one try/catch, and we added retry logic that would have required 4 additional nodes in n8n.
Deployment to production: same day.
When to Stay on n8n
This isn't a "n8n bad, Trigger.dev good" argument. n8n is still the right choice in several scenarios:
- Your team is non-technical. If nobody on your team writes code, n8n's visual interface is genuinely easier to build and maintain.
- Simple workflows. If your automation is "when X happens, do Y" with no complex logic, n8n handles it perfectly. Don't over-engineer it.
- Rapid prototyping. n8n is faster for building a proof of concept. You can wire up a working demo in 20 minutes. Use it to validate the logic, then migrate to Trigger.dev for production.
- Client visibility. Some clients want to see their workflows visually. n8n's canvas is great for that. We still use n8n as the presentation and trigger layer in our hybrid architecture.
The sweet spot for migration is when your n8n workflows have become complex enough that the visual canvas hurts more than it helps — usually around the 15-20 node mark with multiple branches and error handling.
The Hybrid Approach We Recommend
For most clients, we don't fully replace n8n. We use it as the trigger and routing layer, and move the heavy logic to Trigger.dev:
- n8n handles the trigger — webhook, schedule, email, CRM event
- n8n calls Trigger.dev via HTTP request with the payload
- Trigger.dev runs the complex logic — AI reasoning, multi-step processing, error recovery
- Results flow back to n8n for final routing (Slack notifications, CRM updates, etc.)
This gives you the best of both worlds: n8n's visual simplicity for orchestration and Trigger.dev's code-first power for execution. And when you want to fully migrate a workflow, the Claude Code approach makes it painless.
Getting Started
If you want to try this yourself:
- Install Claude Code — available as a CLI, VS Code extension, or desktop app
- Export one n8n workflow — pick a complex one that's been giving you headaches
- Set up a Trigger.dev project —
npx trigger.dev@latest initin your repo - Paste the JSON into Claude Code — ask it to convert to a Trigger.dev v3 task
- Review, add credentials, deploy — you're live
The first migration is the one that convinces you. Once you see a 30-node spaghetti workflow become 80 lines of clean TypeScript, you won't want to go back.
FAQ
Can Claude Code handle any n8n workflow?
It handles the vast majority. Standard nodes (HTTP, Function, If, Switch, Set, Merge, Slack, email) convert cleanly. Highly custom nodes or community nodes may need manual adjustment, but Claude will flag those and suggest alternatives.
Do I need to be a developer?
You need basic comfort with TypeScript and deploying code. If you can read a function and run npm deploy, you're good. Claude Code writes the actual implementation — you review and deploy it.
What about n8n workflows with sub-workflows?
Claude Code converts each sub-workflow into a separate Trigger.dev task, and the parent workflow calls them using Trigger.dev's trigger and wait patterns. The modularity actually improves.
Is Trigger.dev free?
There's a generous free tier for development and small-scale production. Paid plans scale with compute usage, which is typically cheaper than n8n Cloud at high volume because Trigger.dev scales to zero between executions.
Can I migrate gradually?
Absolutely. That's what we recommend. Start with your most painful workflow, migrate it, and keep everything else on n8n. Move workflows over as they need updates or cause problems.
Ready to migrate your most complex workflows? Use our ROI calculator to see how much time you'd save, or book a call and we'll walk through your n8n setup together — no commitment, just an honest assessment of what's worth migrating first.
