Skip to content
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 and can cut install time substantially.
  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 can be faster in specific jobs; it is not universally faster.
  • Package installation and short-script startup can improve visibly.
  • Trivial HTTP benchmarks can favor Bun, while real services may bottleneck on databases or external APIs.
  • Pure-compute results depend on the program and each engine's optimizations.
  • Bundling should be measured against a fast dedicated tool such as esbuild on the actual project.
Measure install time, startup time, and request latency on your workload. A headline percentage is not a production result.

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
Keep the existing lockfile and compare in a separate worktree or copy. Current Bun writes bun.lock; bun.lockb is the legacy pre-1.2 format. If bun run fails where Node succeeds, look up the specific API in Bun’s official Node.js compatibility documentation.

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.