A few weeks ago I deleted two years of work.
Thirty-four automations that run every day — for me and for my clients. WhatsApp AI bots, lead capture from Facebook and web forms, PDF report generation, calendar booking, CRM sync, notifications. All of them built the same way: box after box, dragged and dropped onto a visual canvas.
I deleted the lot and rewrote them in code.
This isn't a "no-code is bad" post. The visual platform I used (n8n) is genuinely excellent and open-source, and it let me ship fast for years. But as the system grew, I started fighting the tooling instead of building. So I want to walk through why code-first won for my use case, the numbers that came out of it, and — importantly — the parts that did not improve, because I have no interest in hype.
What "code-first" actually changed
Here's the before/after, minus the buzzwords.
Maintenance. Before, every change meant opening a browser, hunting for the right node inside a diagram, and dragging. Now every change is a line of code and a git commit. Full history, real diffs, code review, and instant rollback when something breaks.
Building. Before, each new automation was assembled from scratch on the canvas. Now I compose typed, reusable modules. Faster, and consistent across the whole system.
Control. The logic is mine, written explicitly. No magic behind a box, no surprises.
No lock-in. It's standard code in an open format. It runs anywhere; it isn't married to any one platform's JSON schema.
I built on DBOS — a framework that runs workflows written as ordinary TypeScript, backed by Postgres, with durable execution built in. More on that below.
The numbers
The headline that still makes me smile:
Memory: from ~1.4GB down to ~150MB. Roughly 10×.
Same 34 automations, same work, a tenth of the footprint. At idle the new stack sits around 48MB. A smaller, cheaper server now runs the same load with plenty of room to grow.
A couple more measured figures:
| Metric | Result |
|---|---|
| Throughput | ~1,167 workflows/second |
| Per-workflow overhead | ~30ms |
| Idle memory | ~48MB |
| Memory vs. old stack | ~150MB vs ~1.4GB (~10×) |
Where did the memory go before? To scale under load I had to add worker processes and a queue layer — each one eating more RAM. Now the base is so light that most of the time there's simply nothing to talk about.
The honest part (because I hate hype)
The bots themselves are not faster to respond. Here's why: when a bot talks to a large language model, the LLM sets the pace, not the infrastructure around it. The model's "thinking" takes what it takes, and no runtime swap changes that.
So what did I actually gain? A server that breathes, far higher concurrency, and lower infrastructure cost. Stability and efficiency — not the latency of a single reply. If someone tells you a runtime swap made their AI bot "instant," be skeptical.
How one person did all this
Translating 34 live automations to code, keeping behavior identical, testing each one, and shipping to production without a single client noticing — that is not a one-person job. Historically it's a team, over weeks.
I did it solo, working with Claude Code.
In practice it was a dialogue with a tool that reads code like a senior engineer: it helped me understand each existing automation, rewrite it in TypeScript, catch bugs before production, and verify each flow against the original. I direct, decide, and approve; it does the heavy lifting, fast.
And the migration itself was invisible to the outside world. A Caddy reverse proxy routes all the inbound traffic — WhatsApp, webhooks, forms — so every sender kept hitting the same endpoints. I swapped the engine mid-flight; nobody felt a thing.
The takeaway
The real story here isn't DBOS versus n8n. It's that the ceiling moved.
For years we all learned to work inside limits: "too complex to hand-write," "needs a team," "not worth the weeks." A lot of those limits just quietly disappeared, and our habits haven't caught up yet.
So the question I keep asking myself now isn't "how do I do what I already do, a bit faster?" It's "what would I build if the technical barrier weren't there?" Half of my someday-list turns out to be within reach today.
Next article: a technical deep-dive into the one feature that made this migration worth it — exactly-once durable execution — with real code.
Have you moved something from no-code to code-first? What pushed you over the edge? I'd genuinely like to hear it.
Top comments (2)
Your experience with hitting the wall on debugging complex no-code workflows really tracks with what we've seen. We had a suite of critical backend processes built on a similar visual platform, and once they grew beyond trivial branching logic, chasing down a single failure became a multi-hour archaeological dig. The absence of proper version control, robust testing frameworks, and integrated logging meant every change was a prayer, and root cause analysis was pure guesswork.
Moving to a code-first approach, especially with durable workflow frameworks, provides such a fundamental shift in developer experience. Suddenly you're back in an IDE with breakpoints, proper stack traces, and the ability to integrate with existing monitoring tools. It's often counter-intuitive to non-devs, but for a single engineer, a well-designed code-first system can be faster to build and maintain than wrestling with an opaque no-code solution when requirements get complex. The tooling around durable workflows has matured considerably, making that transition less daunting than it might have been a few years ago, particularly for state management and retry logic.
While no-code still has a strong place for simpler, isolated tasks or business-user enablement, for anything touching core business logic or requiring high reliability and performance, the total cost of ownership almost always swings back to code. The control you gain over underlying infrastructure, resource consumption, and freedom from vendor lock-in is a huge long-term win, even if the initial rewrite is a significant investment.
"Every change was a prayer" is the line I wish I'd led with. But I'd push on why — it's not that no-code lacks a debugger, it's that it lacks a diff. When the whole workflow is state hidden inside a vendor's UI, you can't see what changed between the version that worked and the one that broke, so every regression starts from zero. Git didn't just give me breakpoints back; it gave me
git bisect.The dividing line I've landed on isn't complexity, it's whether the workflow has state that outlives a single run. Fire-and-forget "webhook in, Slack out" — no-code is genuinely faster and I'll keep using it. But the moment there's a retry, a partial failure, or a value that has to survive a crash, you're building a state machine whether you admit it or not, and doing that inside an opaque runtime is where the multi-hour archaeology starts. Better to make the state machine explicit and testable than to pretend it isn't one.
Fully with you on lock-in as the long-tail cost — the rewrite is a one-time bill; the opacity is a subscription.