Build the mental model first

Understand Bun's four roles through familiar Node.js tooling

Last updated on

The short version

Bun is not merely a faster npm client. It combines work commonly handled by Node.js, npm/pnpm, Jest/Vitest, and tools such as esbuild into one bun executable.

Familiar roleBun entry pointMust you replace it now?
Node.js runtimebun run app.tsNo; start with scripts or local development
npm / pnpm / Yarnbun installNo; verify lockfiles and lifecycle scripts first
Jest / Vitestbun testNo; migrate isolated unit tests first
esbuild / Rollupbun buildNo; keep framework build tools when required

Two meanings of bun run

bun run server.ts   # execute a file
bun run dev         # execute the dev script in package.json

If a file and a script could share a name, use an explicit path and extension for source, such as bun run ./dev.ts, and bun run dev for the package.json script. --bun does not disambiguate the two; it forces locally installed CLIs that declare a Node.js shebang to run with Bun.

Place flags at the correct boundary:

bun --watch run dev   # --watch belongs to Bun
bun run dev -- --port 4000   # --port belongs to the dev script

TypeScript execution is not type checking

Bun strips TypeScript syntax and executes the result. Keep a real static check in CI:

{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "test": "bun test"
  }
}

Web APIs and Node.js APIs

Bun emphasizes standard Web APIs such as fetch, Request, Response, and WebSocket, while implementing broad Node.js compatibility. Native addons, loaders, framework adapters, and edge cases still require project-specific tests.

A low-risk adoption order

  1. Execute a standalone TypeScript script with bun run.
  2. Reproduce dependency installation with bun install and review bun.lock.
  3. Move isolated unit tests to bun test.
  4. Evaluate the production runtime or full build chain last.