A Year of Bun in Production: A Bug List, a Win List, a Verdict
Bun's performance numbers are real. The compatibility story is mostly real. The bug count is also real. Twelve months of running Bun in production across two SaaS products — what we hit, what surprised us, and what we'd tell a team about to switch.
Last May we moved one of our backend workspaces from Node to Bun, mostly because bun install was twelve seconds and npm install was four minutes and I had run out of patience. A year later, Bun runs every production process in our stack. Anthropic acquired the runtime in December 2025; Bun is the default in Claude Code. The question "is it production-ready?" has effectively been answered by people with bigger payrolls than ours.
That doesn't mean it's been a clean year. Here's the bug list, the win list, and the verdict.
The wins are bigger than the marketing claims
The headline number — "3.7× HTTP throughput" — is real on a synthetic benchmark and almost meaningless in production, because if your handler talks to a database or an external API, the runtime is 3% of your latency budget. But there are other wins, less flashy, that compound day after day.
bun install is so fast it changes how we work. Branch switches that used to mean a coffee break are now instant. The CI step that used to be npm ci and take ninety seconds is six. When you stop dreading lockfile churn, you start updating dependencies more aggressively, and your security posture improves as a side effect.
bun test is a built-in test runner with Jest-compatible APIs, no jest install, no ts-jest, no babel.config.js, no nothing. We deleted four packages from one repo and gained no functionality loss. This is the kind of small win you don't appreciate until you're standing in a new repo on a new machine and you can just write a test.
bun run dev for TypeScript with no separate compile step. bun build for client bundles. bun --watch for hot reload of a server. Each of these replaced a tool we used to install and configure. The reduction in package.json "scripts" alone has been worth the migration.
The bugs are also real
We hit five distinct production bugs in the first six months. Not one of them was a showstopper. None of them was zero either.
Memory growth in long-running workers. Our Convex deployment isn't the issue here — Convex runs its own runtime. The issue was an internal Bun script we use to mirror articles to a CDN, which would slowly climb in RSS over a few hours and OOM around the seven-hour mark. The fix was to restart it via cron every six hours. We never root-caused the leak; it stopped reproducing on Bun 1.2.x. That's an unsatisfying outcome.
A native module that wouldn't compile. We needed sharp for some one-off image processing. sharp uses node-gyp under the hood, and Bun's node-gyp story was rough until late 2025. The workaround was running the image step in a separate Node process. By December the issue was effectively fixed upstream, but for a month we had a hybrid runtime in production, which is exactly the thing you switch runtimes to avoid.
A WebSocket library that quietly misframed messages. A popular ws library worked under Node and emitted malformed frames under Bun, which the receiving client interpreted as a disconnect. The bug was reproducible only when payload size crossed ~16 KB. We pinned an older version, opened an issue, moved on. Three weeks later it was patched. This is the kind of bug that doesn't show up in your test suite because nobody tests cross-runtime WebSocket framing on payloads of arbitrary size.
process.env precedence differences. Bun's .env loading order differs subtly from Node's in some edge cases involving NODE_ENV-derived files. We had one staging environment quietly reading the wrong vars for half a day before we noticed. Fixed by being explicit with --env-file=.
TypeScript decorators behaved differently. Specifically the experimental ones — the new stage-3 standard decorators work fine. We don't use them anymore, but we did, and the migration took an afternoon.
Bun has roughly 4,700 open issues to Node's 1,700. Some of that gap is age; a lot of it isn't. The runtime is mostly good and occasionally weird, and you should plan for occasional weirdness.
The compatibility number is technically true
Bun claims about 95% npm compatibility as of 1.3, and that's roughly accurate. The thing nobody tells you is that the 5% you can't run correlates with your codebase's age. If you're starting a project in 2026 with modern packages, you'll never hit the gap. If you're moving a five-year-old service with some bespoke C++ addon for, say, hardware key signing, you'll hit it on day one and you'll either rewrite the addon or stay on Node.
For us, the 5% was: sharp (above), one Redis client that used a custom resolution path, and an OpenTelemetry exporter that depended on a Node-specific async hook. None were existential. All required workarounds.
The verdict, with caveats
Would we do it again? Yes. Without the year of hindsight, would I tell another small team to switch?
If you're starting a new project in 2026, yes, start on Bun. The dev-experience win is large and immediate. The risk surface for a fresh codebase is small because you won't have legacy modules to fight.
If you have a production Node service that's working, think harder. The performance delta in a real handler is small. The migration risk is non-zero. The right question isn't "would Bun be faster" — it's "what specific pain am I solving by switching?" If the answer is "nothing, I just want to use the cool runtime," stay on Node. If the answer is "our CI is unbearable" or "we want to delete six dev dependencies," those are real reasons.
The Anthropic acquisition matters more than it sounds, because the implicit question behind every runtime adoption is "will this still be here in five years?" Bun's answer to that question is now significantly stronger. It's not a hobby project anymore. It's also not Node's level of maturity yet, and won't be for a while.
If you do switch, do it gradually. We moved one repo first, ran it for two months, then moved the rest. Treat the first repo as a test for your failure modes — your dependencies, your deployment, your monitoring. Bun's bugs and your dependencies' bugs both surface during this window. The repos we moved second went much smoother because we knew what to look for.
One small operational note: keep a node_modules you can rebuild under Node, just in case. We've never needed to fall back, but on the two occasions where we were debugging a runtime-specific bug and needed to confirm "is it Bun or is it us?" the ability to run the same code under both was the fastest way to a diagnosis.
Bun is a JavaScript and TypeScript runtime maintained by Oven, acquired by Anthropic in December 2025. We run it across our SaaS products at Syntax Lab Technology — the field notes above are from the actual repos, not from a benchmark gist.
Ask AI