Overview

Bun is a JavaScript runtime with a built-in package manager, bundler, and test runner. You can use only the package manager and keep running your code on Node. This guide installs Bun, migrates a project’s lockfile, runs scripts and tests, and updates CI. The trade-offs against npm and pnpm are in yarn-vs-pnpm; Bun as a runtime against Node is in bun-vs-node.

Prerequisites

  • macOS, Linux, or Windows 10 1809 or later (Windows is stable).
  • A package.json project. Bun uses the npm registry.

Steps

1. Install

curl -fsSL https://bun.com/install | bash    # macOS, Linux
# or: brew install oven-sh/bun/bun   |   npm install -g bun
bun --version

If bun is not found, add ~/.bun/bin to PATH.

2. Install dependencies and migrate the lockfile

bun install

Without a bun.lock, bun install migrates automatically from package-lock.json (npm lockfile versions 2 and up), yarn.lock v1, or pnpm-lock.yaml, and leaves the original file in place. An npm 6 lockfile (lockfileVersion 1) is not migrated; Bun resolves from package.json instead. Commit bun.lock, a text lockfile since Bun 1.2. To convert an old binary bun.lockb:

bun install --save-text-lockfile --frozen-lockfile --lockfile-only

Then delete bun.lockb. Remove the other managers’ lockfiles once CI passes so two lockfiles do not drift.

3. Trust install scripts deliberately

Bun does not run dependency lifecycle scripts by default, apart from a built-in list of popular npm packages. If a package needs postinstall, allow it:

{ "trustedDependencies": ["sharp"] }

Defining the field replaces the built-in list rather than extending it, and an empty array blocks every script. Dependencies from git:, github:, file:, or link: sources always need to be listed.

4. Run scripts and tests

bun run build          # runs the package.json script
bun test               # built-in Jest-compatible runner; files named *.test.ts
bun add -d @types/bun  # types for Bun.serve, Bun.file (TypeScript projects using the Bun runtime)

5. Update CI

- uses: oven-sh/setup-bun@v2
  with: { bun-version: 1.4.2 }       # pin; or omit to follow package.json packageManager / engines.bun
- run: bun install --frozen-lockfile
- run: bun run build && bun test

--frozen-lockfile makes the install fail instead of rewriting bun.lock, which catches drift. setup-bun caches the Bun executable by default; see set-up-github-actions-cache for dependency caching.

Verify it worked

ls bun.lock && bun install --frozen-lockfile && bun run build && bun test

Common errors

  • bun: command not found. ~/.bun/bin is not on PATH.
  • A package misbehaves after install. Its install script was blocked; add it to trustedDependencies.
  • --frozen-lockfile fails in CI. package.json changed without a refreshed lockfile; run bun install locally and commit bun.lock.
  • A native module fails at runtime under the Bun runtime. Run that part under Node and use Bun only for installs, or pick another package.
  • Workspaces do not resolve. Declare them in the workspaces field of the root package.json.

FAQ

Can I use Bun as a package manager and still run my code on Node?

Yes; use only the package manager and keep running your code on Node. Under the Bun runtime, a native module that fails can stay on Node while Bun handles installs.

Does bun install migrate my package-lock.json?

Yes, when no bun.lock exists, bun install migrates package-lock.json (lockfile version 2 and up), yarn.lock v1, or pnpm-lock.yaml and leaves the original in place. An npm 6 lockfile (lockfileVersion 1) is not migrated.

Why did a package break after bun install?

Bun does not run dependency lifecycle scripts by default, apart from a built-in list of popular packages. Add the package to trustedDependencies, noting that the field replaces the built-in list.

How do I stop Bun from rewriting the lockfile in CI?

Run bun install --frozen-lockfile, which fails instead of rewriting bun.lock and so catches drift.