Bun 1.4 Rewrote Itself in Rust. I Ran My Node App on It Anyway
Somewhere in the last twelve months, my JavaScript toolchain stopped being written in JavaScript. Vite 8 runs on Rolldown, which is Rust. TypeScript 7 compiles with a Go binary. And last week Bun 1.4 shipped, replacing roughly 535,000 lines of Zig with over a million lines of Rust. I already wrote about what the Rolldown switch did to my builds and what the native TypeScript compiler changed. Bun was the last domino, so I spent the weekend pointing my Node API at it.
Short version: it runs. Not everything survived, and the things that broke were exactly the boring ones nobody writes benchmark posts about.
The rewrite itself matters less than you think
Yes, the Zig to Rust migration was a genuinely wild event. The team did it with AI assistance, the diff made half of Hacker News angry, and people counted the unsafe blocks like they were auditing a prison. I get it. But as a user, the language underneath is not my problem. Whether my app still runs is.
That's where the release notes actually get interesting. Bun 1.4 passes 1,517 more tests from the official Node.js test suite than 1.3 did. Idle CPU dropped about fivefold, memory up to 35%, and Linux startup for a hello world went from 10.9ms to 5.1ms. The number I trust most is not from a synthetic benchmark: Anthropic runs Claude Code on the Rust build, and its production p99 CPU fell from 24% to 10% after the switch. That's a real, long-running app under real load.
Module coverage is where it gets concrete. node:events, node:trace_events, and node:sqlite pass 100% of their test suites. node:http, node:fs, and node:stream sit around 97%. That last 3% is where your weird dependency lives. It always is.
What actually broke for me
I pointed a modest Express-style API at it. Application code ran untouched on the first try, which honestly surprised me. Then the environment got involved.
First, env vars. When you run a script with bun directly, it auto-loads .env. But when Bun runs as a drop-in replacement for node, it stopped doing that in 1.4. My config came up empty and I spent an embarrassing ten minutes blaming the wrong thing:
# this does NOT load .env anymore
bun run server.js
# this does
bun run --env-file=.env server.js
Second, native modules. Bun now aligns its ABI with Node 26, so NODE_MODULE_VERSION moved to 147. Anything with a prebuilt binary, like better-sqlite3 or your favorite image library, needs a matching build. If a package doesn't ship one for 147, you're compiling from source or you're stuck.
Third, YAML parsing got stricter. Bun.YAML follows YAML 1.2 now, which means yes, no, on, and off are booleans instead of strings. One of my config files relied on the old behavior. It failed loudly, which I appreciated more than I expected to.
Finally, new lockfiles are version 2 with tighter integrity checks, and brand new monorepos default to an isolated linker instead of the hoisted layout. Existing lockfiles keep the old behavior, so this mostly hits you on greenfield projects.
The twenty minutes I now spend before switching runtimes
I've been burned enough times that I do the same drill every time a shiny runtime lands. It fits in a coffee break:
git checkout -b try-bun-1.4
# does everything install?
bun install
# does the suite pass? run it twice, once with each runtime
bun test
npm test
# does the app boot and answer a request?
bun run dev
curl -s localhost:3000/health | jq .status
If the test suite passes on both runtimes, you've answered the only question that matters: not "is Bun faster," but "can I switch back if this goes sideways." The whole argument for Bun in 2026 stopped being benchmark charts and became something you can verify against your own code. That's the part I find genuinely new.
Where I actually use it now
My split looks like this. CI and throwaway scripts: Bun, no hesitation, installs alone justify it. Local dev servers: Bun. Production traffic for the API with native dependencies: still Node, until I have a maintenance window and a real reason. That's not fear, that's just scheduling.
One last thing I've started doing: every runtime gotcha like the .env change goes into a "runtime gotchas" snippet folder I keep in Snippet Ark, tagged by tool and version. Runtimes are shipping fast enough now that last month's mental model is stale by default. A searchable list of "this changed in 1.4" beats my memory every time.
Bun 1.4 is the first version where "just try your Node app on it" is reasonable advice instead of a dare. Try it on a branch first. Then tell your native modules I said hi.