· bun · tooling · javascript · —
I Replaced npm with Bun. Here's the Honest Scorecard.
Bun promises a faster install, one toolchain instead of four, and a drop-in npm replacement. After shipping real projects on it, here's where it delivers and where the sharp edges still draw blood.
Bun sells itself as three tools in one binary: a package manager, a JavaScript runtime, and a bundler and test runner, all meant to be much faster than the npm stack they replace. I've been running it as the package manager on real projects long enough to have opinions that aren't just first-install euphoria. Here's the honest version.
Fast installs change how you behave, not just your benchmarks
The headline claim holds up. Installs that used to be long enough to make me tab away and lose focus now finish before I've context-switched. That sounds trivial. It changes your behaviour more than you'd expect.
When install stops being a coffee break, you stop avoiding it. You add a dependency to try an idea instead of talking yourself out of it. You delete node_modules without dread. You stop building your CI around elaborate caching, because reinstalling from scratch barely costs anything.
bun install # install the whole tree
bun add motion # add one package, update bun.lock
bun remove lodash # drop oneI'm deliberately not quoting a benchmark multiple here, because yours depends on your dependency tree, your disk, and your cache. The point isn't a specific number. It's that the install got fast enough to stop being a thing you plan around.
bun.lock is a lockfile a human can actually read
Early Bun shipped a binary lockfile, bun.lockb. It was fast and it was miserable to review, because every dependency change turned into an unreadable blob in your diff.
The current text-based bun.lock fixes that. It's a real file that you and your reviewer can read, which matters, because a lockfile nobody can review is a supply-chain risk nobody can see.
bun install --frozen-lockfile # CI: fail if bun.lock is staleCommit it, review it, and treat a surprise change in it the way you'd treat a surprise change in package-lock.json: as a signal worth reading, not noise to wave through.
Package manager and runtime are two different bets
This is the distinction most "should I use Bun" takes skip over. Installing packages with Bun and running your app on Bun are separate decisions with very different risk.
As a package manager, Bun is a low-risk swap. It installs the same npm packages into the same node_modules, so if it ever annoys you, you delete bun.lock, run npm install, and you're back on Node tooling. The exit is cheap.
Running your app on the Bun runtime is a bigger commitment. It's genuinely fast and the developer experience is nice, but you're betting production behaviour on a younger runtime with a smaller battle-tested surface than Node. For a side project, that's an easy yes. For a service that pages me at 3am, I still run Node and keep Bun to dependency management.
The sharp edges
Honesty means naming the parts that cost me an afternoon:
- Ecosystem assumptions. A handful of tools still assume
npmoryarnis the package manager, usually in a postinstall script or a CLI that shells out to a specific command. Rare, but confusing when it lands. - Native modules. Packages with native bindings are where "drop-in" gets tested. Usually fine, occasionally not, and the failure is rarely self-explanatory.
- CI muscle memory. Every cache step, Docker base image, and setup action in your pipeline assumes Node. Switching means touching all of it and getting the lockfile caching right so you aren't silently reinstalling from scratch on every run.
None of these are dealbreakers. All of them are "budget an afternoon the first time, and it's smooth after that."
The scorecard
| Dimension | Verdict |
| Install speed | Excellent, and the real reason to switch |
Lockfile (bun.lock) | Good, readable and reviewable, commit it |
| npm compatibility as a package manager | Strong, same node_modules, cheap exit |
| Runtime maturity | Improving, great DX, younger than Node |
| CI and tooling ecosystem | The friction, everything still assumes Node |
| Reversibility | High, rm bun.lock && npm install |
Where I land
Default to Bun as the package manager on anything new. The speed is free and the exit is cheap, so there's little to lose. Reach for the Bun runtime when the project is small or the DX win clearly outweighs the maturity risk, and stay on Node when the thing has to be boring and bulletproof.
Bun earned a permanent seat in my toolchain as an installer and a probationary one as a runtime. That's not a hedge. It's matching the maturity of the tool to the stakes of the job.
If you want to try it, bun.sh has the one-line installer, and switching an existing project is usually as simple as running bun install where you'd have run npm install.