Bitdoze Logo

Bun Package Manager: Complete Guide vs NPM, Yarn & PNPM

Bun package manager is up to 30x faster than npm. This 2026 guide covers installing Bun, migrating from npm/yarn/pnpm, and using bun.lock, bun outdated & more.

DragosDragos19 min read
Bun Package Manager: Complete Guide vs NPM, Yarn & PNPM

Bun is a JavaScript runtime and package manager built from scratch with Zig and JavaScriptCore. It aims to be a drop-in replacement for NPM, Yarn, and PNPM with significantly faster install times and a simpler toolchain. Since this article was first published in February 2024, Bun has gained full Windows support, a new text-based lockfile, and was acquired by Anthropic in December 2025.

Updated July 2026

  • Native Windows support: Bun 1.1 (April 2024) added full Windows support passing 98% of the test suite. No WSL needed.
  • Text-based lockfile: Bun 1.2 (January 2025) made bun.lock (human-readable JSONC) the default, replacing the binary bun.lockb.
  • Anthropic acquired Bun (December 2025): Bun now powers Claude Code and the Claude Agent SDK. Long-term viability concerns from the original article are largely resolved.
  • New commands: bun outdated, bun why, bun audit, bun update --interactive, bun publish, and bun patch are all production-ready.

Why switch to Bun: bun vs npm, yarn & pnpm compared

The core argument for switching is speed. Bun installs packages in parallel using multiple threads, caches results globally, and can be up to 30x faster than npm on cold installs. On warm installs (cache populated, lockfile present), the difference is even wider.

But speed is not the only reason. Here’s what you get:

  • Up to 30x faster installs (cold) and near-instant warm installs
  • Native Windows, macOS, and Linux support, no WSL needed
  • Text-based bun.lock that diffs cleanly in git PRs
  • Auto-migration from package-lock.json, yarn.lock, and pnpm-lock.yaml
  • Built-in test runner, bundler, and package publisher
  • Backed by Anthropic, powers Claude Code and the Claude Agent SDK

Speed comparison: npm vs pnpm vs Bun

Bun’s own benchmarks claim “up to 30x faster” installs than npm. That number is from their marketing, not an independent source. In practice, the gap depends on your project size, network, and cache state.

The pnpm.io/benchmarks page (daily-updated) compares npm, pnpm, Yarn Classic, and Yarn PnP, but does not include Bun. For npm vs pnpm, the benchmark shows pnpm is roughly 2-3x faster than npm on clean installs. Bun’s real-world advantage over npm is typically 5-15x, depending on the scenario.

Your results will vary. Test on your own project. See the real-world benchmark below for one data point.

When this article was first published, some developers questioned Bun’s long-term viability, drawing parallels with Yarn’s rise and fall. The Anthropic acquisition in December 2025 has largely settled that debate. Bun is no longer a side project. It’s the runtime behind Claude Code.

You can check how to migrate Astro to Bun on CloudFlare for a real migration walkthrough.

How to install Bun on macOS, Linux & Windows

Bun installs on all major platforms. Below are the current recommended methods.

Verify installation

bun --version
# Should print something like: 1.3.14

bun --revision
# Prints the build revision (useful for bug reports)

To self-update Bun:

bun upgrade

CPU compatibility

Standard Bun builds require AVX2 instructions (Haswell-era Intel, Excavator-era AMD or newer). On older CPUs you’ll get an “Illegal Instruction” error. If that happens, install the baseline build: curl -fsSL https://bun.sh/install | bash -s -- --baseline.

If bun is not found after install, make sure ~/.bun/bin is in your PATH. Add this to your shell config:

# bash/zsh, add to ~/.bashrc or ~/.zshrc
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"

For Fish shell, see best Fish shell plugins and tools for PATH setup guidance.

If you need Node.js installed alongside Bun, see how to install Node.js using NVM.

Bun lockfile: bun.lock vs bun.lockb

Before Bun 1.2 (January 2025), the default lockfile was the binary bun.lockb. It worked, but you couldn’t diff it in git, couldn’t review lockfile changes in PRs, and merge conflicts were impossible to resolve by hand.

Bun 1.2 made bun.lock the default. It’s a text-based JSONC file that diffs and merges like any other source file.

Migrating from bun.lockb

bun install --save-text-lockfile --frozen-lockfile --lockfile-only
# Then remove the old binary lockfile
rm bun.lockb

After this, bun install will maintain bun.lock going forward. The binary bun.lockb is still supported for backward compatibility, but there’s no reason to keep it.

Verify: ls bun.lock should exist. Run git diff bun.lock. You should see readable JSONC output.

If bun install still generates bun.lockb instead of bun.lock, check bunfig.toml for saveTextLockfile = false or upgrade your Bun version.

How to migrate from NPM, Yarn, or PNPM to Bun

Since Bun 1.1, bun install can auto-migrate from existing lockfiles. But the cleanest approach is still to remove the old lockfile first, then let Bun generate a fresh bun.lock.

Verify: ls bun.lock should exist, ls node_modules should show installed packages, and bun run build (or your project’s build command) should succeed.

If you run into issues with native addons, check bun pm untrusted. Bun blocks lifecycle scripts (postinstall, etc.) by default since Bun 1.1. See the troubleshooting section below for how to trust packages.

For a full Astro migration walkthrough, see migrate Astro to Bun on CloudFlare.

Bun command reference: essential commands & npm equivalents

Core commands

Bun Command npm Equivalent Purpose
bun install npm install Install all dependencies from package.json
bun add <pkg> npm install <pkg> Add a new package
bun add <pkg> --dev npm install <pkg> --save-dev Add a dev dependency
bun remove <pkg> npm uninstall <pkg> Remove a package
bun run <script> npm run <script> Execute a script from package.json
bun outdated npm outdated Show outdated packages
bun update <pkg> npm update <pkg> Update within semver range
bun update <pkg> --latest npm install <pkg>@latest Update to latest version
bun update --interactive (no built-in equivalent) Interactive picker (Bun 1.3+)
bun why <pkg> npm explain <pkg> Explain why a package is installed
bun audit npm audit Scan for security vulnerabilities
bun publish npm publish Publish a package to npm
bun patch <pkg> npx patch-package Patch a dependency
bun pm pack npm pack Create a tarball for publishing

Checking for outdated packages

bun outdated
# Shows all outdated packages with current and latest versions

bun outdated --filter '@myorg/*'
# Filter to specific scope

Updating packages

bun update <package>            # Update within semver range
bun update <package> --latest   # Update to latest, ignoring semver
bun update                      # Update all deps within semver range
bun update --interactive        # Pick which deps to update interactively

For a deeper dive into updating packages with Bun, see how to update Node packages with Bun and how to update all Node.js dependencies.

Security and trust

Lifecycle scripts are blocked by default

Since Bun 1.1, postinstall and other lifecycle scripts from packages are blocked by default for security. This is a good thing (it prevents supply chain attacks), but it means some packages (like native addons) won’t build until you trust them.

bun pm untrusted          # List packages with blocked lifecycle scripts
bun pm trust <package>    # Trust a specific package
bun pm trust --all        # Trust all packages (use with caution)

Real-world benchmark: Bun install speed test

I ran this test on the bitdoze.com Astro blog. The project has a typical mix of dependencies. Here are the raw numbers:

NPM:

  bitdoze-astro-bkw git:(main) time npm install

npm install  13.22s user 3.82s system 23% cpu 1:13.89 total

npm run build  55.96s user 3.41s system 126% cpu 46.776 total

Bun:

  bitdoze-astro-bkw git:(main) time bun install

bun install  10.83s user 2.14s system 121% cpu 10.694 total

bun run build  55.30s user 3.34s system 126% cpu 46.181 total
Bun install speed benchmark: 11 seconds vs npm's 73 seconds, 7x faster package installation

Results: Bun install took ~11 seconds. npm install took 73 seconds. That’s 7x faster for this project. The build process was identical. The same Astro build runs at the same speed regardless of which package manager installed the dependencies.

This was tested in February 2024 and re-verified in July 2026. Bun 1.2+ is roughly 30% faster than the version originally tested, so the gap has likely widened for new installs. For a look at how Astro 7 improved build speeds, see Astro 7 benchmark: build times cut in half. You can also optimize Astro build speeds further with SSG-specific tweaks.

Your results will vary based on project size, dependency count, hardware, and network conditions.

Bun in Docker & CI/CD: production best practices

Dockerfile example

Bun provides official Docker images. Use oven/bun:alpine for the build stage (smaller, musl-based) and oven/bun:distroless for the runtime (minimal attack surface):

FROM oven/bun:alpine AS builder
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile

FROM oven/bun:distroless AS runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["bun", "run", "start"]

To skip devDependencies in production:

bun install --frozen-lockfile --production

CI/CD with GitHub Actions

Always use --frozen-lockfile in CI

bun install --frozen-lockfile fails if bun.lock is out of date. This catches lockfile drift before it reaches production. Run bun install locally and commit the updated lockfile if CI fails on this step.

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest
      - run: bun install --frozen-lockfile
      - run: bun run build
      - run: bun test

Common failure: if --frozen-lockfile fails, it means your bun.lock doesn’t match package.json. Run bun install locally, commit the lockfile, and push.

For more Docker commands and patterns, see top Docker commands you must know.

Bun usage examples

Add and remove packages

# Add packages
bun add tailwindcss autoprefixer postcss

# Add a dev dependency
bun add prettier --dev

# Remove a package
bun remove tailwindcss

Run scripts

bun run dev      # Run the "dev" script from package.json
bun run build    # Run the "build" script
bun run test     # Run the "test" script

For monorepos with workspaces, run scripts in specific packages:

bun run --filter @myorg/web build

Check and update dependencies

# See what's outdated
bun outdated

# Update interactively (Bun 1.3+)
bun update --interactive

# Update a specific package to latest
bun update tailwindcss --latest

Audit for vulnerabilities

bun audit
# Scans dependencies for known security vulnerabilities

Troubleshooting common Bun issues

"Illegal Instruction" error on startup

Your CPU lacks AVX2 support (pre-Haswell Intel, pre-Excavator AMD). Bun’s standard builds require AVX2.

Fix: Install the baseline build that works on older CPUs:

curl -fsSL https://bun.sh/install | bash -s -- --baseline

Or on Windows:

powershell -c "irm bun.sh/install.ps1 -- --baseline | iex"
bun: command not found

~/.bun/bin is not in your PATH.

Fix: Add to your shell config:

# bash (~/.bashrc) or zsh (~/.zshrc)
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"

Then reload: source ~/.bashrc (or source ~/.zshrc).

For Fish shell, add to ~/.config/fish/config.fish:

set --export BUN_INSTALL "$HOME/.bun"
set --export PATH "$BUN_INSTALL/bin" $PATH
Lifecycle scripts blocked (postinstall failing)

Bun blocks lifecycle scripts (postinstall, preinstall, etc.) by default since Bun 1.1. This is a security measure against supply chain attacks.

Fix:

bun pm untrusted          # See which packages are blocked
bun pm trust <package>    # Trust a specific package
bun pm trust --all        # Trust all (use with caution)

Alternatively, add to package.json:

{
  "trustedDependencies": ["package-name"]
}
Kernel too old on Linux

Bun requires kernel 5.1 minimum, with 5.6+ recommended. It will attempt to run on kernels as old as 3.10 (RHEL 7) with reduced functionality.

Check your kernel:

uname -r

If you’re on an older kernel, consider upgrading or using a newer distro. On shared hosting or managed VPS, you may not control the kernel, check with your provider.

Private registry not working

Since Bun 1.2, Bun reads .npmrc files ($HOME/.npmrc and project-level .npmrc). You can also configure registries in bunfig.toml:

[install.scopes]
"@myorg" = { url = "https://registry.myorg.com", token = "npm_..." }

Or use .npmrc:

//registry.myorg.com/:_authToken=npm_...
@myorg:registry=https://registry.myorg.com
How to roll back to npm

If Bun is causing issues and you need to revert:

rm -rf node_modules bun.lock
npm install

This restores your npm setup. If you kept package-lock.json as a backup, you’ll get your exact previous dependency tree back. If not, npm will generate a new one from package.json.

Frequently asked questions

Is Bun ready for production?

For package management, yes. bun install is stable, fast, and used in production CI/CD pipelines. For the Bun runtime (replacing Node.js), maturity varies by use case. Most teams start by using Bun as a package manager only, running their app on Node.js.

The Anthropic acquisition (December 2025) is a strong signal. Bun powers Claude Code and the Claude Agent SDK, which means Anthropic has a direct business interest in Bun’s reliability.

Does Bun work with private registries?

Yes. Since Bun 1.2, Bun reads .npmrc files for auth tokens and scoped registry configuration. It also supports bunfig.toml for Bun-specific configuration. Both $HOME/.npmrc (global) and project-level .npmrc are supported.

Can I use Bun in monorepos?

Yes. Bun supports npm-compatible workspaces. Bun 1.3 added --linker=isolated for pnpm-style strict dependency resolution and catalogs for centralized version management across packages.

For simple monorepos (a few packages), Bun works well. For complex monorepos with deep dependency trees and strict hoisting requirements, pnpm’s mature tooling may still be safer.

How does Bun handle disk usage?

Bun uses a global cache at ~/.bun/install/cache but creates full node_modules copies in each project. This means pnpm (which uses hard links) saves more disk space when you have many projects on the same machine.

If disk space is tight and you run dozens of projects, pnpm is the better choice for disk efficiency. For a handful of projects, the difference is negligible.

Should I use bun.lockb or bun.lock?

Use bun.lock. It’s been the default since Bun 1.2, it’s human-readable, and it diffs properly in git. bun.lockb is only relevant if you’re on Bun 1.1 or earlier, or if you explicitly set saveTextLockfile = false in bunfig.toml. There’s no reason to choose the binary format on a modern Bun version.

Conclusion

Bun as a package manager is production-ready and significantly faster than npm, yarn, or pnpm for install times. The text-based bun.lock, full Windows support, and Anthropic backing have addressed the main concerns from when this article was first published.

My recommendation: try Bun as a package manager on your next project. Remove the old lockfile, run bun install, and see how it feels. You can always roll back if something breaks.

The runtime side (replacing Node.js) is a separate decision with more nuance. But for bun install vs npm install? There’s no contest.