Open source, honestly
Contents
Open source comes wrapped in generous promises: anyone can contribute, fork what you don’t like, more eyes make better code. I’ve spent two decades watching those promises meet reality, and what follows is the honest inventory.

I make open source, I depend on it, and I read it constantly. So take this as an inventory from the inside. Two things decide how to read it, and they come first.
How to read this
First, this is a snapshot. It’s how the field looks to me in 2026. Ask me ten years ago and it was a different place; ask in ten years and it will have moved again. I’m describing what I see. Judging the idea of open source is a different post.
Second, a possibility is worth having even when nobody uses it. People today can fly across a continent, which medieval people could only dream of. Few of us do, so day to day the difference is small, but it’s good the option exists. Open source is the same. It grants a degree of freedom: to contribute, to fork, to read. Most of that freedom sits unused, and that’s fine; the having of it is the point. The first three promises below are these freedoms, so read them as freedoms.
The open source field
Start with what open source actually is, before what it ought to be.
It’s mostly libraries and frameworks; a shipped open application is the exception. It’s written by programmers, rarely designers, so in my experience the few open applications tend to be rough wherever a user would touch them, popular ones included. (The exception is commercial products that open their source; those arrive with professional design already attached, and they’re a separate case I’ll get to.) The open applications that do exist are frequently command-line utilities, which need less design work and are easier to produce and package. Quite a few of the projects with a UI are actually a web server with a browser front end. And open source is built by programmers for programmers. Who else looks at a problem and thinks, “I should start an open source project for that”? A programmer builds for the one market they actually know: their own. What I’d use — or what I think I’d use.
The motives for publishing vary more than people assume:
- To learn. “I started this project to learn X” is said out loud, constantly: a GitHub search for “I started this project to learn” turns up nearly 500 repositories.
- A neat idea with no commercial path. A clever, usually technical idea that resists being turned into a product, so it ships as open source instead.
- Marketing, for a person. A portfolio piece, a hiring signal.
- Marketing, for a startup. Open source as insurance for a prospective client: “if we adopt this and you go under, can we keep it alive?” Published source is the answer.
- Marketing, for a corporation. A sponsor that can’t or won’t commercialize an idea lets (sometimes pays) its programmers to publish it. The return is image: a reputation that attracts better people.
- To set a standard. Free and readable lowers the bar to adoption, and adoption is what makes a solution the standard in practice.
- To preserve hard-won knowledge. A project can be the material record of concentrated experience. That one is my own reason, and it’s the subject of the companion to this post, so I’ll leave it there.
Then there’s commercial “open source,” which is its own thing. Often it’s published snapshots rather than open development: periodic dumps of an internal codebase, and sometimes only the free tier of a paid product. It’s readable, but not steerable. Anyone can read the code and file a bug, but a bug report works inside the existing design and leaves the architecture where it is. Hold on to that distinction; it comes back later.
And a lot of what’s out there is rough or narrow. Rough, because so much of it is the learning exercises and one-offs above, written for the author’s own use. Narrow, because “I had an itch and scratched it” fits exactly the one case it was born for. When I go looking for something specific, I find a dozen near misses, each configurable into everything except the thing I actually need.
“Anyone can contribute” — but almost no one does
The first promise is the big one: anyone can read the code, so anyone can improve it. True — as a freedom. But the freedom and its exercise are different things, and in my experience few users contribute.
Some are happy with what’s there and have no itch to scratch. Some lack the skill to make a meaningful change. Some lack the time. Some lack the motivation: there are people who are roughly the opposite of GNU, “why should I give something away for free?”, and for them it is a matter of principle. And few people are ready to maintain what they wrote. It is a time sink, and they know it. None of that is a failing; it’s just what “anyone can” turns into in practice.
There’s a barrier on the maintainer’s side too, and I’ve built it myself: failing to convey a project’s philosophy and where it’s going. A focused bug fix is easy to take. But substantial contributions often go unused, or get reworked, because they pull away from where the project was headed, and the contributor had only the code to read, because the intended shape lived in my head.
Even a contribution I accept has a price, because a maintainer buys it wholesale. The contributor rarely comes back to fix the problems found later. Most changes add complexity, too. So every merge is future work, and enough of them leave the maintainer doing an unpaid job. That’s why, as a maintainer, I value ideas for enhancements and bug reports more than code. The code itself is cheap, as I argued in Code is cheap. A large pull request is its own beast: it may contradict the project’s ideas, its technical style, and so on. Price-performance matters as well: patching a minor hole, where “don’t do that” would do, can bring in a lot of rarely used code and unrelated concerns, and the code gets harder to maintain for next to nothing.
The complexity is taxing even with my 50 or so projects, and I have no idea how Sindre Sorhus manages more than a thousand. It’s cognitive load. For a maintainer it means more interacting parts to keep track of; for a user, a bigger API and more docs to remember. So rejecting a change, a new feature especially, can be active management of that load. Each change can be sound on its own while the load grows with every one of them, as I described in Death by a thousand reasonable decisions.
I’ve been on the other side of the desk as well, the user sending fixes upstream, and watched the promise meet reality there too:
-
Neglect. Sometimes the patch was going to sit there unread. The maintainer had moved on, or the project was abandonware.
-
Rejected, then reworked. Sometimes a fix was turned down and then reappeared, folded into a larger patch. Usually innocent: the project’s internal code had drifted so far from the published version that my change failed to merge, and rebuilding it was easier than untangling the collisions.
-
The corporate runaround. Corporate-run projects have a move all their own:
— “Rejected — it’s already fixed.”
— “No, it isn’t.”
— “Yes, it’s in a new version.”
— “Where is it?”
— “Not published yet. Just wait.”After a long enough wait it does get “published” (pushed to a public repo), and it still isn’t fixed.
That last one is the readable-not-steerable point in practice: anyone can read their code, outsiders can’t steer it, and the public repo lags behind the real one.
“Don’t like it? Fork it” — but most projects go stale
The second promise: if a project falls short of what you want, fork it, fix it, send the change back; worst case, run your own copy. The same remedy covers a maintainer who loses interest or disappears. It works: LibreOffice is a fork of OpenOffice.org, MariaDB of MySQL, and Valkey of Redis. And yet a startling number of projects, including interesting and even popular ones, simply go stale. The amount of abandonware out there surprised me.
When a maintainer steps away, three things can happen. Best case, they hand the project to a successor and it continues under the same name. A handoff, of the whole project or a share of it, is also how attackers get in: event-stream was backdoored by a volunteer who had offered to take over its maintenance, and xz by a contributor who had become a co-maintainer, as The cost of dependencies tells. Sometimes several users fork it in different directions, the forks are mutually incompatible, and now the users have the commercial world’s problems (discoverability, marketing, picking a winner) with none of its budget. Worst case, and the most common one, the project just lies there unused. Some of those abandoned projects have real value in them, but that’s a story for later in this series.
“More eyes make better code” — where the eyes look
The third promise from the opening holds where the eyes look. Days before this post went out, OpenSSH fixed sshole: on Linux systems built on the musl C library without PAM (pluggable authentication modules), Alpine Linux among them, a password longer than 256 characters logged into accounts with password login disabled. Its finder, Özgün Kültekin, traced it to two old decisions, one in each project. musl’s crypt() refuses a password that long and signals the failure with *. Since 2016, OpenSSH has hashed a password even for an account with no usable hash, so the response time doesn’t reveal which usernames exist. A disabled account stores * as its hash, so the two matched. Each decision was reasonable on its own, both projects are maintained, and the bug needed both. Each project’s reviewers read their own code, and this bug lived where the two meet. It was found about ten years after the second decision.
“The source is the product” — except when the product is a service
The fourth promise assumes the code is the thing: ship the source and the product has shipped. That’s less and less true, because more and more projects are services.
The reason is engineering first. A growing share of what gets built is a service at heart. Dump the source and the service still has to be run: infrastructure, scaling, performance, availability, the whole bill, and that bill grows with every real user. Often it includes other paid services and datasets underneath. Running it once, for everybody, amortizes that cost across all of them; that is why offering it as a service is the practical move as well as the commercial one.
So the project splits in two. The service is commercial, usually with a free tier to bring users in; the rest (the framework, the web app, the client, the SDK) ships as open source. The valuable part is the service, and the service is what costs a competitor real money to reproduce. Vercel is the obvious example: a major presence in the React world, with serious open-source holdings (Next.js chief among them) and a paid platform that hosts its customers’ applications. The code is open; the hosting is what customers pay for, because standing it up themselves is real work.
“Run it yourself” rarely closes that gap. Increasingly, an open source product ships wrapped as a container to host yourself, and even then the user is assumed to have some DevOps skills. The instructions may exist, but self-hosting is hard or expensive at small scale, and a small project can’t mount real competition anyway, especially against a team whose development pace keeps them permanently ahead. I expect more of this: the split into open code and a commercial service is going to keep spreading.
“People build what’s useful” — no, they build what they’re curious about
The fifth promise is really an assumption: that open source drifts toward what’s useful, as a market would. It doesn’t, for two reasons.
First, real competition is limited. There is some: databases, web frameworks on the server and in the browser, message queues. But measured by usage, a category usually has two or three major projects, not hundreds: PostgreSQL and MySQL among open source databases, React, Angular, and Vue in the browser. Visual components are the exception: they can number in the hundreds, with no obvious leader. Anyone can start a database of their own, and few programmers ever start one. The field is so large that anyone who could compete with a given project is usually off building something else. Most projects are ego-driven in the plain sense: “I have an idea, I want to build it.” Reimplementing someone else’s project is rarely fun, unless someone pays for it. I feel the same pull: even choosing what to work on, I want the thing to interest me, and plenty of useful, worthy projects fail that test.
Even an apparent collision can turn out to be two different ideas. In 2005 two “competing” web frameworks appeared on the Python scene: Django and TurboGears. Django came from web developers at a newspaper in Lawrence, Kansas: Adrian Holovaty and Simon Willison, later joined by Jacob Kaplan-Moss. Willison was a computer science student from England, there on a placement. The idea was to give newspapers a way to create custom, event-specific websites fast. So the goal was a developer experience as simple and frictionless as possible, while maintaining the performance of the websites it produced. TurboGears came from Kevin Dangoor and others, as a way to integrate pieces already available in the ecosystem into one cohesive package. That was a smart idea: pick the best, remove the rough edges, and the result is a great web publishing platform. Both projects occupied the same niche for completely different reasons. The perceived head-butting, which I wrote about at the time, happened mostly because they were released publicly at about the same time.
Second, useful and motivating are different things. A project can be important and still fail to make anyone open their editor on a weekend. Linus Torvalds didn’t start Linux because he wanted IBM to profit from it, or because it would one day run Redis — he wanted to understand how an operating system worked. A good deal of open source is exactly that: small, impractical experiments that the person who built them happened to enjoy.
Money accelerates; passion originates
None of this is a complaint, and here is why.
Money speeds open source up, a lot. React came out of Meta, TensorFlow out of Google, Visual Studio Code out of Microsoft; Linux runs on a whole roster of corporate sponsors. There are many ways to grow a project, and money is a strong one. But at the bottom of every one of them is a person, or a few people, with enough passion to do the silly little experiment in the first place. We don’t have to guess at the order of operations: the history of science is the same shape. Funding scales and directs the work; curiosity starts it.
Money is scarcest in maintenance. Curiosity starts a project, but it rarely keeps a critical library patched for decades. When Heartbleed was found in 2014, OpenSSL was widely used by HTTPS servers, and its foundation took in about $2,000 a year in donations, with one developer working on it full time. The xz compression library was kept by one maintainer, unpaid, in his spare time. Russ Cox concludes: “Relatively small investments in OpenSSL and xz development could have prevented both the Heartbleed vulnerability and the xz attack.” OpenSSH’s home page says the same of itself: “OpenSSH is incorporated into many commercial products, but very few of those companies assist OpenSSH with funding.”
So open source works anyway, because the thing at the root of it was never the money: passion starts the projects, and the missing money shows in their maintenance. It’s just how it is, and it’s enough.
Summary
Three things:
- The promises of open source are freedoms, not guarantees, worth having even when unused.
- The field as it really is: mostly rough, mostly abandoned, rarely contributed to, increasingly service-shaped.
- Money accelerates, but passion originates, as in science, and maintenance is where the money runs short.
If that’s the field, the next question is practical: how do you tell a good project from a bad one before you depend on it? That’s the next post in this series.
Open source posts
The series so far, in order:
- Working in the open — why I publish my work: what I learn on a job stays with that job, and what I publish comes with me.
- Open source, honestly — this post.