Open a fresh terminal. Pick the most common starting
point for a modern web project, the one a bootcamp will
tell you to take this week:
npm create vite@latest my-app -- --template react-ts.
Three minutes later, npm install settles.
The shell returns. The project has not yet run.
What is on disk:
- Roughly 250 to 400 MB in
node_modulesfor the leaner choice, Vite + React + TypeScript - A typical Next.js install reaches 700 MB to a full gigabyte, the majority devDependencies
- Around 100,000 to 220,000 files
- 30 to 50 packages listed in
package.json - 1,200 to 1,800 packages actually pulled in, the transitive closure
- A maintainer count in the hundreds, often four-figure
You have not written a line. You have already accepted the work of a small town's worth of strangers, each free to publish a new version overnight, and each free, in the npm trust model, to do almost anything on the next install.
This is the ordinary case. Not the edge case. The starting point.
The point of this Bow is not that one thing in this picture is broken. The point is that four things broke at the same time, each independently against the lean principle that the engineer's head should be free for the work, and each, on its own, would deserve its own diagnosis. Together they have produced a software stack that is, in the precise sense, unauditable: nobody can tell you, with a defensible line, what runs on the next install.
One: The Count Was Never Justified
A modern web project arrives with one to two thousand packages, several hundred megabytes of disk, and a hundred thousand files. None of this is required by what the project actually does. HTMX delivers reactivity to a browser in fourteen kilobytes minified, around five gzipped. MediaWiki runs sixty million Wikipedia articles on a server-rendered PHP stack with no SPA. GOV.UK is mandated to progressive enhancement and ships HTML-first. Hacker News is rendered server-side in Common Lisp. Hotwire, in production at Basecamp, gives full reactivity over the wire. Cloudflare replaced the standard nginx+Lua web tier with a Rust service, Pingora, and runs around seventy per cent less CPU at one trillion requests per day.
The 700 megabytes are not a consequence of what the application needs. They are a choice. The alternatives are not theoretical; they are running, today, at scale.
Two: The Boundary Was Never Drawn
A node_modules directory has no
responsibility line. Not because the code is open
source — so is libc, and nobody reads libc
either. The line is absent because the architecture
never drew one.
There is no boundary between your application code and
the 1,500 packages it pulls in. They run with the same
permissions. They can read each other. The post-install
script of any one of them can modify the others. The
latest tag can shift retroactively, as the
axios maintainer found on the morning of 31 March 2026.
The maintainer of a popular package can be socially
engineered, or simply hand over the keys.
libc, by contrast, has a line: it lives in the base
source tree of an operating system, maintained by
named engineers in a foundation with a public roadmap,
released on a regular cadence, with reproducible builds
and signed artifacts. You do not read it. You know
where it lives, who is accountable for it, and
how it arrived on your disk.
node_modules has none of these.
Three: The Workaround Became Architecture
Node.js arrived in 2009 with a single-threaded event loop. Multi-core hardware required multi-container deployment, because the runtime could not use the cores. The fix was more containers and an orchestrator to schedule them.
Two decades later, the container is the unit of thought,
not the deployment artefact: a minimal Node.js image is
150 MB, the convenient default a full gigabyte, and
dockerd at 183 containers has been
documented above five gigabytes of memory. The
container architecture is not the right answer to
isolation. It is a workaround for a language that
cannot use the machine, dressed up as architecture.
Amazon Prime Video returned its video monitoring to a monolith, a ninety per cent cost reduction. Segment consolidated 140 services into one. Istio merged its control plane back into a single binary. The reversal is happening. The original architecture was sold by advertisement, not by parts removed.
Four: The Layers Hide What They Should Bound
The ORM hides the SQL. The cache hides the ORM. The service mesh hides the services. The operator hides the YAML, which hides the kubelet, which hides the container, which hides the process. Each layer was, in its origin, an idea about containing complexity, so that an engineer could reason one layer at a time.
Somewhere between Dijkstra's 1968 THE Operating System paper and the modern stack, the verb shifted: containing became postponing. Layers no longer keep their lower neighbour from leaking; they exist to defer the moment of examining it. Lehman's second law of software evolution, written in 1974, said it plainly: complexity rises unless explicit work is done to reduce it. The reduction is the work nobody is funded to do.
These are four diagnoses. They share a system. None of them, on its own, is the whole problem.
Eighteen Wednesdays, One Investigation
Each of the four breaks deserves its own week. None can be honestly handled in a paragraph. The next four Wednesdays take the axes one at a time — the count, the boundary, the workaround, the layers.
Then three pillars, across the rest of the summer and into the autumn. npm in detail (15 July – 12 August): the registry that wasn't a service but a market; the code quality question with names attached; the maintainer economy that the system asks for and does not pay for; the audit industry that sells the cure for the disease the registry sells as a feature; the alternatives that did not win, and why. Docker in detail (19 August – 16 September): image bloat as a default; the container escape register; the orchestrator stack; the resource cost; the firms walking back, in their own words. Teams and the labour market (23 – 30 September): how sprint-shaped organisations produce service-shaped architecture; how the hiring filter locks both in.
And the closing Wednesday, 7 October, asks what could still be.
The Point
The 700 MB are part of the problem. So is the rest of what follows. Four things broke at once, each defensible at the time it was introduced, each compounded by the next, each kept in place by an industry that has no interest in reducing it. The result is not a system that occasionally fails. It is a system that is, on its own terms, unauditable: large where it could be small, ungoverned where it could be bounded, oddly shaped where it could fit the machine, layered where it could be plain.
This is what the rest of the Bow will take, one Wednesday at a time. The first cut, not the last.
Next Wednesday: the count, and why none of it was justified.