← Writing

Reinventing the wheel is cheap now

·6 min read·AI

"Don't reinvent the wheel" is one of the first things anyone told me about programming, and for most of my career it was right. Writing code was slow, and somebody else had already spent the hours. Pulling in their package was the cheapest way to borrow those hours.

Coding agents changed one side of that trade. Writing a small, well-specified piece of code now takes minutes. The other side, what a dependency costs you after you install it, hasn't changed at all. So the advice is now wrong for a large class of problems, the small and boring ones, which are most of what we install packages for.

The advice was always a price comparison

"Don't reinvent the wheel" is an estimate: my hours writing and debugging this thing are worth more than the cost of depending on someone else's version. For a decade, that estimate came out the same way almost every time, and the npm ecosystem is what you get when a whole industry follows it to the end.

Illustrative chart comparing two costs. Before coding agents, writing a small piece of code yourself costs far more than depending on a package, so you install. With coding agents, writing it yourself costs almost nothing, while the cost of the dependency is unchanged.
Illustrative, not measured. Only one bar moved.

In March 2016 a developer unpublished left-pad from npm after a dispute over a package name. It was eleven lines that padded a string on the left. Builds broke across the internet, including projects like Babel and React, because thousands of codebases had decided eleven lines weren't worth writing.

That was the joke version. The serious versions came later. In March 2024 someone found a backdoor in xz, a compression library that sits under SSH on most Linux machines. The attacker had spent about two years contributing patiently until they were trusted to ship releases. It was caught because Andres Freund, a developer at Microsoft, noticed SSH logins taking half a second longer than they should. In September 2025, a phishing email took over the npm account of the maintainer of chalk and debug, and the versions published from it rewrote crypto wallet addresses in the browser. Those packages are downloaded billions of times a week, mostly by people who wanted colored terminal output.

What a dependency costs after you install it

A dependency is a stranger with commit access to your production build. Trust is only part of what it costs.

You inherit their release schedule. Their breaking change becomes your migration sprint, on their timing. I know this from the other side: when we shipped PandasAI 2.0 we removed features people relied on, for good reasons, and every one of those removals was a bill we sent to people who had never met us.

The abstraction comes with it too. A package is built for everyone who might use it, so you get the configuration surface for thirty use cases when you have one. You end up writing adapters around it, and the adapter often ends up longer than the code you needed.

So does everything it depends on. You install one package and get forty, each one a separate maintainer, a separate account that can be phished, a separate person who might get bored or bought.

Diagram: your app depends on one package you chose, and that package pulls in a grid of forty more, each one a maintainer, an account and a release schedule you don't control.
One install, forty strangers. Illustrative.

None of these costs went down with AI. If anything they went up, because agents attack cheaply too, and an npm account is easier to get into than your build server.

What changed: the small wheel is free

What did go down is the price of writing the thing yourself, when the thing is small.

This site is a decent example. Its RSS feed is generated by a 76-line script. The sitemap is 75 lines. The Italian version runs on a 63-line file of translations and helpers, not an i18n framework. Each of those had a well-known package I could have installed instead, and each was written with an agent in less time than reading the package's docs would have taken.

I can also read all of it. When the sitemap needed to list the Italian posts, I didn't open an issue or search for a plugin. The change went into a file I'd already read top to bottom. Code you own and fully understand is cheaper to change than code you rent, and agents made that kind of code cheap to produce.

Where the advice still holds

The same site still depends on remark to parse markdown, shiki to highlight code, and three for the 3D shape on the homepage. I'm not rewriting any of those, unless one of them becomes core to what I'm building.

The test I use now has three questions.

Can I describe the whole job in a paragraph? "Read every markdown file, take the title and date from the frontmatter, write an XML feed" fits. "Parse markdown" doesn't, because markdown is a decade of edge cases and arguments about what a nested list means. When the spec fits in a paragraph, an agent can implement it and I can check it.

Is the correctness in the code, or in the years? Date and time zones, cryptography, parsers, database drivers, anything handling money: the value of those libraries is the bug reports they've absorbed, not the lines. An agent will write you a time zone converter that looks perfect and is wrong for one day a year in a country you've never been to. Use the library that already took that bug report.

Would I read it all? If the honest answer is no, writing it myself gives me the costs of a dependency without the years of fixes. Generated code you never read is a dependency on a stranger too, one with no users and no issue tracker.

Flowchart of three questions: does the job fit in a paragraph, is the correctness in the code rather than in years of bug reports, would I read all of it. Yes to all three means write it. A no to any of them means install the library, because its history is worth more than control.
The test I run before installing anything.

If the answer to all three is yes, write it. A small, readable, tested file with no transitive graph beats a package you'll never audit.

Wheels come in sizes

There's one case where I'd replace even a deep library: when the general version is slow for my particular job. A bike, a truck and a race car all have wheels, and nobody fits truck wheels to a race car. Most libraries are the truck wheel. They're built to carry everyone's load, so they handle inputs you'll never send and run checks you'll never need. A CSV library has to cope with quoted fields, strange encodings and line breaks inside cells. If every file you read comes out of your own exporter with the same twelve numeric columns, a parser written for exactly that file can skip most of that work, and on a hot path the gap can be large.

That used to be a project you started only with a profiler printout and a free week. An agent writes the tailored version in an afternoon now, so the risk has moved from "too expensive to try" to "shipped without checking". Before the tailored version replaces the library, I want three things. First, a benchmark on real data against the current release of the library, configured properly, because libraries often have a fast mode nobody turned on. Second, a gap that matters to someone: 40 milliseconds off a nightly job isn't worth a file to maintain, and 40 milliseconds off every request might be. Third, the library's own edge cases run against my version, because inputs drift, and one day my exporter will write a comma inside a field.

Build small things, depend on deep ones

I wrote in July that cheap building moved the value away from code. This is the same shift seen from inside a codebase. When writing is cheap, the expensive parts are the ones you don't control: other people's release schedules and other people's accounts.

So my default flipped. I used to install first and write only when no package fit. Now I write first for anything that fits in a paragraph, and install when the problem is deep enough that the library's history is worth more than my control over the code.

If you think the maintenance bill on all that small code catches up with me in two years, I'd like to hear it, especially if you've already paid it. Tell me.