C.W.K.
Stream
Lesson 04 of 05 · published

Bun — A JS Runtime That's Also a Toolchain

~11 min · tooling, bun, runtime

Level 0Node Curious
0 XP0/40 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Bun is what happens when someone asks: what if the runtime, the package manager, the bundler, and the test runner were the same program?"

What Bun Is

Bun (Jarred Sumner, 2022) is a JavaScript runtime + toolchain in one binary. Written in Zig. Uses JavaScriptCore (Safari's JS engine) instead of V8. Three main capabilities:

  1. Runtimebun script.js runs a script like node script.js, mostly Node-compatible.
  2. Package managerbun install installs npm packages, 5-20x faster than npm.
  3. Bundler / test runnerbun build, bun test as built-in tools.

All three sit in one 50MB binary. npm install -g bun and you have a self-contained Node-shaped ecosystem with no further dependencies.

The Compatibility Story

Bun aims for Node compatibility. Most popular npm packages work on Bun unchanged. The runtime implements Node's built-in modules (fs, http, node:crypto) plus the Web APIs Node has (fetch, Web Streams) plus its own Bun-namespace APIs (Bun.serve, Bun.file).

Where compatibility breaks: native addons (some N-API modules), specific worker_threads patterns, niche http2 behaviors. The gap shrinks every release. For most application code, the gap is invisible.

The Speed Story

Bun is faster than Node in several places, similar in others:
  • Cold start: ~30-50% faster than Node. JavaScriptCore boots quicker than V8.
  • HTTP server throughput: 2-3x higher requests/sec for trivial endpoints. Most real services are bottlenecked elsewhere.
  • Package install: 5-20x faster than npm, depending on cache state. This is real and measurable.
  • Bundling: comparable to esbuild (both are AOT-compiled languages).
  • Pure compute: roughly Node-equivalent; both use modern JS engines.
Speed differences in the real world depend heavily on what you measure. "Bun is X% faster" headlines often measure microbenchmarks that don't reflect production workloads. Try your actual code; the answer varies.

When to Use Bun

Reasonable answers in 2026:

  • As a faster npm — use bun install in projects that ship Node code. Faster installs, no other changes.
  • For dev scriptsbun run scripts/build-something.ts is faster than npx tsx and ships TS support without configuration.
  • For small services where startup time matters — short-lived workers, CLIs, FaaS functions.
  • For new projects where you don't have Node-specific compat needs — Bun-first stack from day one.

When to stay with Node: established Node services, anywhere using a Node-specific feature Bun hasn't shipped, anywhere with strict version-locked devops.

Bun-Specific APIs

Bun ships APIs that don't exist in Node:

// Bun.serve — Bun's fast HTTP server
Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response('hi from Bun');
  },
});

// Bun.file — file API that's not fs
const file = Bun.file('./data.json');
const json = await file.json();
const size = file.size;

// Bun.spawn — fast subprocess (replaces child_process.spawn)
const proc = Bun.spawn(['ls', '-la']);
const output = await new Response(proc.stdout).text();

If you commit to Bun, these are nicer than the Node equivalents. If you want to keep the option to switch back, stick with Node stdlib and treat Bun's compatibility as the bridge.

Pippa's Confession

I tried Bun for a side project, fell in love with the speed, then ran into a Node-only dependency that didn't work. Spent two hours debugging. Switched back to Node. Two days later I tried Bun for just install on the same project, kept Node as runtime. That worked perfectly. Dad's note: "You don't have to pick one for everything. Use Bun where it earns its keep; use Node where it stays the safer bet." Most projects of mine now use bun install + node runtime — the best of both, at the cost of one extra binary on disk.

Code

Bun's CLI surface — the whole toolchain·bash
# bun install — fast package manager
bun install                # like npm install, faster
bun add react              # like npm install react
bun add -d typescript      # like npm install -D typescript
bun remove unused-pkg      # like npm uninstall

# bun run — script runner with TS built-in
bun run scripts/build.ts   # no compile step, works
bun run test               # runs package.json's test script
bun --watch script.ts      # built-in watch mode

# bun test — test runner (jest-flavored)
bun test                   # runs *.test.{ts,tsx,js,jsx}
bun test --watch

# bun build — bundler
bun build src/index.ts --outfile=dist/index.js --target=node
Bun.serve vs Node http — what the porting cost looks like·javascript
// A Bun-flavored HTTP server — Bun.serve
const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);
    if (url.pathname === '/') return new Response('hi from Bun');
    if (url.pathname === '/data') {
      // Bun.file streams from disk without buffering
      return new Response(Bun.file('./big.json'));
    }
    return new Response('not found', { status: 404 });
  },
});
console.log(`listening on http://localhost:${server.port}`);

// Same code, ported to Node — uses standard http module
import { createServer } from 'node:http';
import { createReadStream } from 'node:fs';

createServer(async (req, res) => {
  if (req.url === '/') return res.end('hi from Node');
  if (req.url === '/data') {
    res.setHeader('Content-Type', 'application/json');
    return createReadStream('./big.json').pipe(res);
  }
  res.writeHead(404).end('not found');
}).listen(3000);

External links

Exercise

Install Bun (curl -fsSL https://bun.sh/install | bash). Pick a Node project you already have. Run bun install instead of npm install. Time both, compare. Then try bun run for the dev script vs node. Compare cold start and dev iteration. Decide whether you want bun install + node, full bun, or stay on node. The data informs the choice better than any blog post.
Hint
If bun install complains about lockfile mismatches, run it fresh: rm -rf node_modules bun.lockb && bun install. If something fails on bun run that worked on node, that's the compatibility frontier — check Bun's nodejs-apis docs for the specific feature.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.