Bun: what to read to really understand the runtime
Hacker News reopened the usual thread: Ask HN: What are you reading?. These threads tend to fill up with fiction, biographies and the odd software architecture classic. While reading one, I caught myself thinking about something else. What I read most these days, outside of books, is about Bun. I use Bun every day and realized I understand little of what runs underneath. So here's my answer to Ask HN, dev edition: what's worth reading to really understand Bun, not just type bun install on autopilot.
Why read about Bun instead of just installing it?
Because Bun does way too much in a single binary. It's a runtime, package manager, bundler, test runner and, in recent versions, a client for Postgres, SQLite, S3 and Redis. When everything works, great. When something breaks, you don't even know which of those pieces to look at.
With Node this is easier. The error comes from npm, Jest, webpack or pg. Each one has its own repo, its own issues and its own Stack Overflow. With Bun, everything comes from the same place. That's convenient, but it's also a single point of surprise.
There's also the context. Bun was acquired by Anthropic in late 2025 and became an infrastructure piece for AI coding tools. It stopped being an exciting project from a small team. Today it's a serious dependency for a lot of people. It's worth knowing where you're stepping.
Start with the Bun changelog, not the benchmark
The benchmark is the first thing everyone sees. "4x faster than Node." Cool. But a runtime benchmark measures a hello world serving HTTP, and your app spends 80% of its time waiting on the database.
The changelog tells a different story, and it's the more useful one. On the Bun blog, each release lists:
- what became compatible with Node APIs that were missing before
- bugs fixed in
node:http,node:crypto, streams - behavior changes in
bun installand the lockfile
Reading the changelog is how I figured out why one of my tests only failed in CI. It was a behavior difference in a Node module that had been fixed two versions after the one pinned in the pipeline. Ten minutes of reading would have saved me an afternoon.
Benchmarks tell you how fast. Changelogs tell you how reliable.
My strong opinion of the day: if you run Bun in production and have never read its changelog, you're trusting the marketing. Read the last three releases. It takes less time than a TV episode.
What the Bun docs answer that you didn't know
The official documentation is better than it looks. The problem is we only open it when we're already in a hurry.
Some pages worth reading slowly:
- Node.js compatibility: lists module by module what's complete, partial or missing. Before migrating a service, start here.
- bun install and lockfile: explains the text-based
bun.lock, which replaced the binarybun.lockb. If your team still has the binary file in the repo, it's time to migrate. The PR diff is readable now. - Bun.serve: shows routes, WebSocket and streaming in a single API. Lots of people run Express on top of Bun without needing to.
An example of what you can do with zero dependencies:
Bun.serve({
port: 3000,
routes: {
"/health": new Response("ok"),
"/users/:id": (req) => Response.json({ id: req.params.id }),
},
});
That replaces an Express app with two handlers. I'm not saying you should throw Express away tomorrow. I'm saying that, for a small service, you might never have needed it.
Is reading Bun's source code worth it?
Yes, with adjusted expectations. Bun is written in Zig and uses JavaScriptCore, Safari's engine, instead of the V8 used by Node and Deno. You don't need to know Zig to get value out of it. You need to know where to look.
The GitHub repo has two parts I recommend:
src/js: a good chunk of the Node-compatible APIs is written in TypeScript and JavaScript. You can read hownode:fsornode:eventsis implemented without knowing any Zig.test/: the tests show expected behavior better than any doc. Want to know if an edge case is supported? Find the test.
The Zig part is dense. I read it out of curiosity, not need. But understanding that Bun swaps V8 for JavaScriptCore explains a lot: faster startup, a different memory profile and, sometimes, GC behavior that doesn't match what you measured on Node.
And if you want a laugh, search for old issues titled "works in Node". It's the most popular literary genre in the repo.
What changes in your project when you understand Bun
Reading about Bun changes concrete decisions. Here are three that already changed for me.
Databases without an extra driver. Bun has built-in SQLite and Postgres clients. For scripts, seeds or internal tools, I stopped installing pg and better-sqlite3:
import { sql } from "bun";
// reads the connection from DATABASE_URL
const activeUsers = await sql`select id, email from users where active = ${true}`;
import { Database } from "bun:sqlite";
const db = new Database("cache.db");
const item = db.query("select * from cache where key = ?").get("home");
Shell scripts in TypeScript. Bun.$ runs shell commands with automatic escaping and works the same on Linux, Mac and Windows:
import { $ } from "bun";
const branch = (await $`git branch --show-current`.text()).trim();
await $`echo deploying ${branch}`;
That scripts/deploy.sh that only works on the machine of whoever wrote it can become a .ts everyone can run.
Test runner. bun test accepts the Jest API (describe, it, expect). On a small project, migrating meant deleting the Jest config and swapping the command in package.json. On a large project with heavy module mocking, it wasn't that simple. That's where the compatibility page saves your day.
Where Bun still bites
No hype: Bun isn't Node with a turbo. It's a different runtime that speaks Node's language. Most of the time the translation is perfect. Sometimes it isn't.
The places where I still see problems most often:
- Native addons: packages with binaries compiled for Node (N-API) usually work, but not always. Test before promising a deadline.
- Tools that read Node internals: some APMs and profilers depend on V8 details. On JavaScriptCore they simply have nothing to lean on.
- Deploy platform: not every provider supports Bun natively. Vercel already offers a Bun runtime for Functions, but check yours before switching.
The rule I follow is simple. Bun as a package manager and test runner: use it without fear. Bun as a production runtime: use it, but load test your real use case and keep the changelog open in another tab.
My answer to Ask HN
If someone asked me in the thread what I'm reading, I'd say: the Bun changelog, the Node compatibility page and the repo's test/ folder. It's not bedtime reading. But it's what gave me back the most hours at work this year.
A tool you don't understand becomes magic, and magic in production always sends the bill on a Friday night. Reading about Bun for half an hour a month is cheap insurance. If you want to see where I use this in practice, take a look at my projects.
LinkedIn summary
I use Bun every day and realized I understood very little of what runs underneath. It's a runtime, package manager, bundler and test runner, and it even ships Postgres and SQLite clients. When something breaks, you don't even know which piece to look at. What saved me the most hours this year was the changelog, not the benchmark. The benchmark shows speed. The changelog shows how much you can trust it. Ten minutes reading the latest releases would have saved me a whole afternoon hunting a test that only failed in CI. I also read the Node compatibility page and the test/ folder in the repo. The tests explain expected behavior better than any doc. A tool you don't understand becomes magic, and in production that magic sends you the bill on a Friday night. I wrote the full guide on what's worth reading. If you use Bun too, tell me what caught you by surprise. #Bun #JavaScript #TypeScript #NodeJS #WebDevelopment