In June I wrote that composition is the actual feature — that every tool speaking the same language, lines of text on stdin and stdout, means the tool you need usually already exists as a combination of tools you have. I meant it about the shell and I still do. But I wrote it in the same season that the JavaScript ecosystem committed hard to the opposite bet, and I have spent six weeks watching that bet pay off without adopting it, and I have stopped being able to give myself a straight answer about why.
What actually shipped
Two things landed close together this summer.
Vite+ reached beta at the start of July. It bundles Vite, Vitest, Rolldown, tsdown, Oxlint and Oxfmt behind a single vp command with a monorepo-aware task runner, MIT licensed, framework-agnostic, with more than 1,300 public repositories depending on it. The pitch is aimed precisely at people like me: developers who "do not want to assemble their toolchain by hand again and again."
And TypeScript 7 shipped as a native Go port, with Microsoft measuring speedups between 8x and 12x on full builds — the VS Code source going from 125.7 seconds to 10.6, with aggregate memory down around 18 percent.
I want to be careful with these numbers, because this is a space where numbers get rounded in the direction of the story. The figure that travels is "TypeScript 7 is 10x faster." Microsoft's own claim is a range that depends on the codebase, and they name the benchmark, so I'd rather use their range and their example than the round number that got detached from it. There's a counterclaim going around that real-world monorepos see closer to 3x; I couldn't trace it past a single post with no published methodology, so I'm not using it either. And the Vite+ announcement includes a download chart whose own alt text labels the headline figure a prediction from partial-month data, which is why I quoted the repository count instead.
What's left after that pruning is still unambiguous. The integrated toolchain is faster, and it is faster by an amount that changes how a working day feels.
The argument I made, and where it doesn't hold
Here is the part I got wrong, and it took me a while to see it because the mistake was in the analogy rather than in the conclusion.
Pipes work because the interface between two programs is a stream of bytes and nothing else is shared. rg does not need to know what fzf thinks a file is. That independence is exactly what makes the composition free — there is no shared state to keep consistent, so there is no cost to gluing arbitrary tools together.
Build tooling is not like that. Every tool in a JavaScript project is looking at the same source files and building the same model of them. Consider what a hand-assembled setup actually does:
Five commands, and four of them independently parse every file in the project into an abstract syntax tree, then throw it away. That is not composition. That is the same expensive work done four times because the tools have no way to share it. The "interface" between them isn't a stream — it's the filesystem plus four config files that have to agree with each other about what TypeScript version you're on and which files are excluded.
So when Vite+ puts Oxlint and Oxfmt and Rolldown behind one command, the win isn't packaging. Those tools are built on a shared foundation in a way five independently-chosen binaries can never be, and the redundancy above is what disappears. I should be honest that this is my reading of the architecture rather than a benchmark I can point at — I haven't seen anyone publish the parse-cost breakdown, and I'd want to before I put a number on it. But the shape of the argument holds regardless of the size of the win, and it's a shape my instinct wasn't going to reach. I assumed a bundle was a marketing artifact wrapped around tools that were fine separately. In this domain that was just wrong.
What it cost anyway
Which brings me to the thing I actually want to argue, now that I've conceded the technical point.
The cost of an integrated toolchain isn't performance and isn't licensing. It's that the seams disappear, and the seams were where I did my debugging.
When my hand-assembled setup broke, it broke at a boundary I could see. The type checker disagreed with the bundler about module resolution; I could run each one alone, compare, and find the config line responsible. Ugly, slow, and mine. When vp check fails in a way I don't understand, the boundary is inside someone else's process. I'm not saying that's worse in expectation — it will fail far less often, and that probably nets out positive. I'm saying the failures I do get will be ones I can't decompose, and I have no calibration yet for how bad that is.
The second cost is the one I keep seeing framed as a licensing question, which I think is a mistake. VoidZero — which employs the people behind Vite, Vitest, Rolldown and Oxc — joined Cloudflare in June. The reflexive worry is about control, and the reflexive rebuttal is that it's all MIT and forkable, and the rebuttal is correct. If Cloudflare did something hostile tomorrow, the code would fork by the weekend.
But forking code is the easy half. What you can't fork is the attention of the people who understand it. The risk isn't that the licence changes; it's that the roadmap for the entire toolchain now has one set of commercial priorities behind it, and that "we're not prioritising that" from a single employer covers what used to require six separate maintainers to independently not care. That's a quieter failure than a licence change, it has no clause you can point at, and I don't have a way to measure it — which is probably why it gets left out of the discussion in favour of the licensing argument that has a clean answer.
Where I might be wrong
The strongest case against everything above is that I'm mourning a capability almost nobody used.
I have never swapped the bundler on a project. I have never composed my JavaScript toolchain in any sense that would make a Unix person proud. What I actually did, every time, was copy a config from a template, adjust two lines, and not touch it again for a year — and when something broke I searched the error message rather than reasoning from the boundary I've just spent two paragraphs praising. The seams I'm defending were, for me, mostly decorative. I looked at them roughly twice.
If that's true for me it's true for most teams, and then the honest description of what Vite+ removes is not "composability" but "the illusion of composability, plus six config files." Which is a good trade at any price.
I think there's something left after that concession, but it's smaller than I'd like. It's this: the option to look inside is worth something even when it's rarely exercised, in the same way that a fire door is worth something even though you don't use it. The difference is that I can't tell from here whether I'm describing a fire door or a doorknob I liked the feel of.
Why I still haven't adopted it
And here's the part I owe myself, since this post is mostly me working out a contradiction in public.
I have a defensible-sounding case above for being cautious. But I don't think caution is why I haven't run vp migrate. I think I haven't run it because my current setup works, changing it would cost me an afternoon, and I have been dressing that inertia up as a position about software architecture. Those are very different things and only one of them is worth writing about.
The tell is that my objections are all about failure modes I haven't experienced, on a tool I haven't installed, while the benefits are measured and published and reproducible. That's not skepticism. That's a preference looking for a justification, and the fact that I can write a decent paragraph in its defence is exactly what makes it hard to notice.
The point
The pitch isn't that integrated toolchains are bad. They won, they won on the merits, and the reason they won is a real technical argument about shared state that my shell-shaped instincts were never going to reach on their own.
The narrower claim is that "this is faster and simpler" and "this concentrates something that used to be distributed" are both true at once, and that the second one is easy to stop mentioning once the first one is settled. I'd rather say it out loud now, while I still remember what the previous arrangement was for — because the version of me that adopts Vite+ next month is not going to be able to reconstruct this argument, and probably won't want to.
Sources
- Announcing Vite+ Beta — VoidZero — the primary announcement, and the source for the tool list, the MIT licence, the 1,300+ dependent repositories, and the download chart whose alt text labels its headline figure a prediction.
- Announcing TypeScript 7.0 — Microsoft — the vendor's own benchmark, including the 8x–12x range and the VS Code build measurement I use in place of the rounder figure in circulation.
- VoidZero is joining Cloudflare — VoidZero — the ownership change behind the toolchain, announced by VoidZero rather than reported secondhand.
The claim that four separate tools redundantly parse the same files is a description of how the tools work rather than a measured figure, and the argument that a shared foundation removes that cost is my own reading rather than a published benchmark. Both should be read that way. The "3x on real monorepos" counterclaim to Microsoft's numbers is excluded above because I could only trace it to a single post with no stated methodology — if someone publishes that measurement properly I'd want to revisit the paragraph it would have gone in.