All writing

Boring Is Not In-Distribution

The relapse

The essay came back

Dan McKinley's Choose Boring Technology hit the Hacker News front page again on 13 August 2026. Eleven years old, 326 points. Its argument is a budget: every company gets about three innovation tokens, you spend them on whatever makes you money, and every other choice goes to the dullest thing that works.

What is different in August 2026 is the rewrite in the comments. The reframing that set the tone arrived within half an hour:

Using the language of the article, I'd say “push all your innovation tokens into agents” is probably a good move. This means the tech your agents work with should all be boring tech. Another way of saying this is “use in-distribution technology”. If agents are substantially better at Rust than Zig, probably you should use Rust, even if Zig is “better”. The amount that Zig is better is going to get swamped by the amount that in-distribution agents are better.

It is a substitution. Boring became in-distribution, and teams are making architecture decisions on the new variable while citing the evidence for the old one.

A year of measurements says those are different properties, and that the proxy joining them barely beats a coin.

The counterexample

Rails is as boring as it gets

On February 3, 2026, DHH put the thesis in one sentence:

Convention over configuration set the path for 20+ years of great training data for AI to use today. Not only does this mean agents do great with Rails, but also that squishy humans can quickly and confidently review the output without a jungle of distracting boilerplate.

Evil Martians maintain a scorecard. The headline, verbatim: “given a free choice, 13 models picked Ruby 0 times in 1,267 solutions.” Their one-line diagnosis: “Models reach for what they can see.”

The scorecard measures what models choose, not how well they write Ruby once you make them. Nobody has published that second number.

Even so: Rails is boring, uniform, twenty years documented, and models given a free hand never reach for it. Boring does not predict in-distribution, and Rails is the proof.

The measurement

Popularity barely beats a coin

The most useful paper named the thing everyone is gesturing at: AI coding proficiency, the degree to which a model can use a given technology to produce good code, measured across 170 third-party libraries and six models.

Functionally equivalent libraries differ by up to 84% in the quality of the code models write with them.

Quality gap
84%
between functionally equivalent libraries
Popularity concordance
0.574
with AI proficiency across 188 pairs, Cohen's d of 0.15
Leader changes
86.17%
of pairs pick a different winner on a different model

The paper's popularity proxy is GitHub stars, which stands in for corpus representation rather than for maturity. Across 188 competing library pairs, the concordance between popularity and AI proficiency is 0.574 (95% CI 0.503–0.643), with a Cohen's d of 0.15. They describe that, correctly, as “only a weak positive correlation.” In 80 of those 188 pairs popularity pointed the wrong way: DVC has 2.12 times TensorBoard's stars and scores 6.46% lower on GPT-4o. In 86.17% of competing pairs, the leading library changes depending on which model you ask.

Treat it as a preprint: first posted September 2025, revised June 2026, with a model set that includes GPT-4o rather than only 2026 frontier models.

A March 2025 study revised in June 2026 found models pulling in NumPy unnecessarily in up to 45% of cases. On high-performance initialisation tasks, where Python is the wrong tool, they chose it 58% of the time and reached for Rust not once. Their conclusion, verbatim: “LLMs prioritise familiarity and popularity over suitability and task-specific optimality.”

The churn

The model's taste turns over faster than yours

In February 2026, Edwin Ong and Alex Vikati probed Claude Code 2,430 times across three models, four project types and twenty categories. Some categories are closed: GitHub Actions takes 93.8% of CI/CD, Stripe 91.4% of payments, shadcn/ui 90.1% of UI components, Vercel 100% of JavaScript deployments. Postgres takes 58.4% of databases.

The fear is that models freeze your stack at whatever was popular during training. The data says the opposite, in the study's own words: “Within each ecosystem, newer models pick newer tools.” Prisma, released 2019, went from 79% of JavaScript ORM picks under Sonnet 4.5 to 0% under Opus 4.6. Drizzle, released 2022, went from 21% to 100%. Celery went 100% to 0%. Redis lost caching to framework-native alternatives.

Those are within-ecosystem numbers from single project types, and ORM/Database sits in the study's least stable bucket for prompt phrasing. Across the whole study, rephrasing the same question flips the top recommendation about 24% of the time.

Custom/DIY implementations account for 252 of 2,073 primary picks, or 12%. It travelled as “92% of Claude Code's Picks Are Custom Solutions”: the same 252 over the wrong denominator.

The lever

Documentation is the only lever anyone measured

In April 2026 someone finally priced it: 270 real API updates across eight Python libraries, eleven models, four families. Without comprehensive documentation in context, 42.55% of generated code examples execute. With structured documentation supplied, 66.36%.

The authors call that second number “low.” A third of the code still does not run with the docs sitting right there.

Svelte's Paolo Ricciuti described the low point. Models mixed Svelte 5 runes with Svelte 4 syntax because they had seen so much more of the old one, and worse: “inspecting the system prompts of the top labs showed they were directly nudging the LLMs towards the most popular choice: React.” Svelte's answer was llms.txt, an MCP server, an autofixer and Skills.

The xyflow team tried the same menu and reported honestly: llms.txt materially improved output, while hand-written Skills mostly kept the agent on task and were not worth the effort, because “current LLMs already appear to have a great handle of React Flow already.”

I ran the check on 14 August 2026. react.dev, nextjs.org, svelte.dev, bun.com, prisma.io, docs.djangoproject.com, hono.dev, nuxt.com and vite.dev all serve /llms.txt. tailwindcss.com, astro.build, fastapi.tiangolo.com, postgresql.org and docs.python.org return 404.

Django shipped in 2005 and serves the file; FastAPI is from 2018 and does not; Astro is from 2021 and does not. Maturity predicts nothing here. Effort does, and effort is purchasable: a two-year-old library can acquire in an afternoon the property you were told to pick a twenty-year-old library to get.

The receipts

What the token actually bought

Bun rewrote itself from Zig to Rust in eleven days, May 3rd to merge on May 14th: about fifty dynamic Claude Code workflows, sixteen Claudes per worktree across four worktrees, peaking at 1,300 lines a minute, 6,502 commits, a landed diff of +1,009,272 lines, zero tests skipped or deleted, and “around $165,000 at API pricing.” The stated reason is not training data but that use-after-free and double-free become compiler errors in safe Rust: “compiler errors are a better feedback loop than a style guide.” Every one of those numbers comes from the team that did the rewrite.

Eleven weeks later, Tom Lockwood asked how it was going (496 points) and reported no release tag and thousands of open automated PRs. The comment that lands hardest is not about Rust at all:

someone decided to try to fix the issues in the Zig original and is now claiming sub-second build times, plus fixed bugs, by modernizing the codebase and sticking with best practices - indicating that all of the issues that justified the rewrite were self-inflicted and addressable.

The boring option was never Rust or Zig. It was fixing what you already had.

Meanwhile Roc went the other way, Rust to Zig, and Richard Feldman published the retrospective in July, 531 points and 487 days to parity. He classified every bug report by whether memory corruption was involved and concluded: “picking a different row would have made no appreciable difference to the project.”

Two teams, opposite directions, a million lines and 487 days between them, arriving at the same place: the language choice did not decide the outcome.

The steelman

Boring may become irrelevant

The strongest case against the whole framework came from Alexandru Nedelcu in March 2026, and it attacks McKinley's cost model rather than his conclusion. Every line McKinley priced is deflating: “The cost of refactoring for switching tech stacks, programming languages included, is going to zero.” Training new people, converging to zero. Dependency upgrades, “goes to zero, becoming an automated process, even when it involves API breakage.” His conclusion inverts the usual one: pick Rust, Scala, OCaml, F#, Haskell, because “static, expressive type systems provide the most bang for the buck (optimal token usage).”

If switching stacks were approaching free, Bun's eleven days would have ended in a release rather than a 496-point thread asking where it is. The arithmetic has not landed yet.

Simon Willison expected agents to be the ultimate argument for boring technology. In March he wrote that dropping an agent into a codebase built on libraries “too private or too new to feature in the training data” works “just fine — the agent will consult enough of the existing examples to understand patterns, then iterate and test its own output to fill in the gaps,” and that “in practice they don't seem to be affecting my technology choices in that way at all.”

His update contains the distinction this entire debate has been missing: “The issue of what technology LLMs recommend is a separate one.” Recommendation bias is measured, repeatedly, by everyone. Capability deficit is assumed.

In eighteen months Vite, pnpm, Yarn, uv, Bun and the TypeScript compiler all moved to non-boring runtimes, and the r/rust thread on pnpm's Rust migration put it plainly: “Notably, Typescript is using Go... Let's take it as a win for the community that they're moving to languages that are safer, more performant, and easier to maintain.” Boring-technology advice, applied as written, blocks every one of those moves. Every one of them paid off.

That same thread had a commenter attacking the metaphor itself:

“Boring” means nothing, it's a vague proxy term. “Well tsted”, “performant for our use case”, “developers know it”, etc mean something.

He is right, and it is worse than he says. Every property the word stands in for can be measured. Boring is the only one nobody is ever asked to measure.

The gap

Nobody ran the experiment

No benchmark measures agent success on new versus mature technology while holding task difficulty constant. Not one.

The closest anyone has come is a June 2026 polyglot study in which two frontier agents built 34 chess engines across 17 languages, several with no comparable open-source prior, LaTeX among them. Every language produced a working engine. And yet: “strong playing strength is only reachable in mainstream compiled languages, cost and engineering effort grow sharply as the language becomes more exotic.” One domain, one paper.

Faros AI's April 2026 telemetry across 22,000 developers shows the incidents-to-PR ratio up 242.7% between low and high AI adoption cohorts. Bugs per developer rose from +9% in last year's report to +54% in this one. It is a vendor reporting on its own customer base, and it is the largest sample anyone has published. METR re-ran its own study and found an 18% speedup for returning developers where it had previously measured a 19% slowdown. Then it called the new data “an unreliable signal” because developers kept refusing to take tasks without AI. The 2025 slowdown cleared significance. Both 2026 speedup estimates cross zero.

McKinley's innovation tokens bought down operational risk: can we run this, can we hire for it, do we know how it fails at 3am. The cost that went up instead is verification: knowing whether what was just written for you is correct.

  • Measure itRun both candidates through the prompts you actually write. An afternoon settles what a decade of GitHub stars cannot
  • Ship the docsDocumentation in context moved executable output from 42.55% to 66.36%. Your dependency either serves it or it does not
  • Grade the outputVerification is the cost that rose. Prefer what your test suite and your reviewers can prove wrong

So the question worth asking about a technology in 2026 is not whether it is boring. Ask whether a model writes it well, which is measurable and which nobody measures; whether its documentation is in the context window, which you can fix this afternoon; and whether you can tell when the output is wrong, which is now the whole job.

Boring was always a proxy for “someone else already found the bugs.” The proxy broke this year, in public, and the industry re-architected around the replacement without ever running the experiment. The method is published. It is 188 pairs long. Somebody go run it.