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.jsonproject. 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 --versionIf bun is not found, add ~/.bun/bin to PATH.
2. Install dependencies and migrate the lockfile
bun installWithout 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-onlyThen 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 testCommon errors
bun: command not found.~/.bun/binis not onPATH.- A package misbehaves after install. Its install script was blocked; add it to
trustedDependencies. --frozen-lockfilefails in CI.package.jsonchanged without a refreshed lockfile; runbun installlocally and commitbun.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
workspacesfield of the rootpackage.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.