Skip to content
Julien DanjouJulien Danjou
August 3, 2026 · 8 min read

Build vs. buy, after LLMs made building look cheap

LLMs collapsed the cost of the first 80% of any tool. That's exactly the part that was never the expensive part. Here's a framework for deciding what to build and what to buy when a prototype is an afternoon away.

Ask an LLM to build you a merge queue, a feature-flag service, or a CI cache, and you’ll have something running by lunch. It will work on the happy path. It will demo well. And it will quietly reset your team’s intuition about what that tool costs to own.

That reset is the trap. The first 80% of an infrastructure tool was never the expensive part. LLMs made the cheap part cheaper, and left the expensive part exactly where it was.

The cost was always the tail

Every piece of developer infrastructure has the same shape. A small core that’s easy to write, wrapped in a long tail of edge cases, operational duties, and failure modes that only show up under real load.

The core is the part an LLM nails. A queue that rebases and merges in order. A flag that flips on and off. A cache that keys on a hash. That’s the afternoon.

The tail is the part nobody writes in the prompt:

  • The edge cases. Squash versus rebase versus merge commits. Conflicts that resolve mid-flight. Checks that go red between staging and landing. Each one is a separate code path with its own invariant.
  • The operations. Someone runs this at 2am when it wedges. Someone upgrades it when the API it depends on changes. Someone adds the dashboard the team actually asks for.
  • The failure modes. What happens when it’s wrong, how loudly it tells you, and how hard recovery is.

You don’t spend fifteen days building it and one day running it. You spend the fifteen days, ship it, and then run it forever.

costtime →Buildone-timeRun, every month, foreverThe prototype is the cheapest moment in the tool’s entire life.
The afternoon prototype shows you the build spike and hides the band that runs forever.

A framework that survives cheap prototypes

The build-vs-buy questions didn’t change. LLMs just made it tempting to skip them. Ask these four before you commit a team to owning something.

Is it differentiating? Does this tool make your product better in a way your customers can feel? Build the things that are your edge. Buy the things that are everyone’s plumbing. Nobody’s customers pay them for the merge queue they built in-house.

Is it run-once or run-forever? An LLM is great at the script you run once and throw away. A one-off migration, a data backfill, a proof-of-concept. The economics flip when the thing has to run every day, because then you’re not buying a script, you’re hiring its maintenance.

What’s the blast radius when it’s wrong? Some tools fail loud and local. Others fail silent and global. The further toward silent-and-global, the more the correctness work dominates, and that work is most of the cost. A tool whose worst case is “main is corrupted and nobody noticed for four hours” is not an afternoon project, no matter how good the afternoon was.

Who owns it in two years? The person who built it will move teams. The tool stays. If you can’t name the team that owns it after the original author is gone, you’re not building a tool, you’re building future toil.

Run the framework

None of this is hypothetical. Put a real tool through the four questions and the answer usually falls out.

  • A one-off data migration. Not differentiating, run-once, small blast radius. Build it, with an LLM, this afternoon, and delete it when it’s done. This is exactly what the new tools are best at.
  • An internal dashboard only your team sees. Undifferentiated, but cheap to run and low blast radius. Build or buy, it barely matters. Don’t overthink it.
  • A merge queue, a secrets manager, an auth layer. Undifferentiated, run-forever, high blast radius on every axis. Buy. The prototype will work in the demo, and the bill arrives every month after.
  • Your actual product. Differentiating by definition. Build. This is the whole reason not to spend your best engineers on the rows above.

The pattern is consistent. Build the things that are yours, or throwaway. Buy the things that are everyone’s, and permanent.

The maintenance illusion

There’s a second trap underneath the first. If an LLM can build it, surely an LLM can maintain it?

Sometimes it helps. But the model didn’t carry the pager last night, doesn’t know which invariant is load-bearing, and won’t be the one explaining why main was wrong for four hours. Maintenance isn’t mostly typing. It’s judgment, context, and accountability, and none of those come out of a prompt. The run cost is mostly human, and it stays human no matter who writes the code.

What LLMs actually changed

They didn’t make build cheaper than buy. They made the prototype cheaper, which is a different thing. The prototype is the part you were never paying a vendor for.

Used well, that’s a real gift. Build the differentiating, run-once, low-blast-radius things yourself, faster than ever. Buy the undifferentiated, run-forever, high-blast-radius ones, because the bill there was always the tail, and the tail is still yours if you build it.

The merge queue is the cleanest example of the high-blast-radius case. We wrote up when it makes sense to build your own, and when it doesn’t.

Stay ahead in CI/CD

Blog posts, release news, and automation tips straight in your inbox.

Recommended posts

We put Jinja2 in our config for flexibility. Users wanted one variable.
July 1, 2026·8 min read

We put Jinja2 in our config for flexibility. Users wanted one variable.

We gave users a full templating engine in their config, then scanned 4,629 of them to see what they did with it. Across 6,873 label values, exactly one held a template. Here's what that taught us about shipping flexibility.

Thomas BerdyThomas Berdy
Most aria-labels on your buttons are dead weight, and some are bugs
June 22, 2026·6 min read

Most aria-labels on your buttons are dead weight, and some are bugs

An aria-label doesn't add to a button's accessible name, it replaces it. Here's why most of the ones you sprinkle on buttons are redundant, and how a few quietly break voice control and fail WCAG.

Alexandre GaubertAlexandre Gaubert
We Spent Years Hardening Jinja2 in User Config. We're Removing It Instead.
May 20, 2026·5 min read

We Spent Years Hardening Jinja2 in User Config. We're Removing It Instead.

After years of patching a Jinja2 sandbox against hostile templates, we pulled every customer config, learned what users actually did with the feature, and replaced it with a narrow declarative schema.

Thomas BerdyThomas Berdy