| | |

Bun 04 ⚡ Installing Dependencies with Bun’s Ultra-Fast Lockfile (bun.lockb)

⏱️ Estimated read: 8 min | |

Bun’s package manager is defined by its lockfile strategy. For its first two years, Bun used a binary lockfile named bun.lockb, which was faster to parse but opaque to review, Git diffs, and merge tools. In December 2024, Bun introduced a text-based alternative (bun.lock), and since Bun v1.2, it has become the default. This chapter covers both formats, the migration path, and the --frozen-lockfile mechanism that makes CI installs deterministic.

Key point: Bun v1.2 changed the default lockfile from binary bun.lockb to text-based bun.lock. The text format is diffable, mergeable, and 30% faster for cached installs. Existing projects must migrate explicitly; bun install alone does not rewrite the lockfile format.


Why Bun’s lockfile evolved

The binary review problem. Binary files cannot be reviewed in pull requests, merged with standard Git tooling, or inspected without running Bun. The bun.lockb format prioritized parsing speed at the cost of every downstream workflow: code review, merge conflict resolution, and CI diffing . The Bun team acknowledged that the most common feedback from teams migrating from npm, pnpm, or Yarn was about this binary format .

The text format advantage. bun.lock is JSONC (JSON with comments), similar to tsconfig.json. GitHub renders it in diffs, VS Code syntax-highlights it, and merge conflicts can be resolved by hand . The performance cost is negative: cached installs using the text lockfile are 30% faster than cached installs with the binary lockfile. A benchmark from Bun v1.1.39 showed 45.8ms for text versus 60.4ms for binary on a warm cache .

The migration problem. Bun does not automatically rewrite bun.lockb to bun.lock. The migration requires an explicit command: bun install --save-text-lockfile --frozen-lockfile --lockfile-only, followed by deleting the old binary file . Running bun install on a project with an existing bun.lockb continues to use the binary format unless this migration is performed.

The CI determinism problem. --frozen-lockfile is the flag that makes lockfile verification mandatory. It installs the exact versions recorded in the lockfile and fails if package.json and the lockfile disagree. The bun ci command is a convenience alias for bun install --frozen-lockfile .

The trade-off. The text format is slower to parse on a cold install, but faster on warm installs due to better caching. The binary format is smaller and faster to parse but incompatible with standard review workflows. The text format is the future; the binary format remains supported for backward compatibility .


a. Installing dependencies and generating the lockfile

The bun install command reads package.json, resolves the dependency graph, downloads packages, and writes the lockfile. In Bun v1.2+, the default lockfile is bun.lock. In earlier versions or projects with an existing bun.lockb, the binary format is used unless migration is performed.

# Standard install (writes bun.lock in v1.2+)
bun install

# Generate the lockfile without installing to node_modules
bun install --lockfile-only

# Install without modifying the lockfile
bun install --no-save

The --lockfile-only flag resolves dependencies and writes bun.lock without creating node_modules or populating the global cache with packages. It is useful for generating a lockfile in CI or for reviewing dependency changes before installation .

Bun automatically migrates existing lockfiles from other package managers when no bun.lock exists. The supported formats are package-lock.json (npm, lockfileVersion 2, 3, or 4), yarn.lock (Yarn v1), and pnpm-lock.yaml (pnpm v7+) . The migration happens during bun install; the original lockfile is not deleted.


b. Migrating from bun.lockb to bun.lock

The migration command generates the text lockfile using the existing binary lockfile as the source of truth, preserving all resolved versions and metadata.

# Generate bun.lock from bun.lockb
bun install --save-text-lockfile --frozen-lockfile --lockfile-only

# Remove the old binary lockfile
rm bun.lockb

The --save-text-lockfile flag tells Bun to write bun.lock instead of bun.lockb. The --frozen-lockfile flag prevents any resolution changes during the migration. The --lockfile-only flag avoids installing packages, making the migration fast and safe .

Once bun.lock exists, bun install uses it and ignores bun.lockb. The binary file can be deleted after the migration. Bun will continue to support the binary format for some time, but the text format is the default for all new projects .


c. CI installs with frozen lockfiles

The --frozen-lockfile flag is the CI safeguard. It ensures that the install uses exactly the versions recorded in the lockfile and fails if package.json has changed in a way that would require a lockfile update.

# CI install
bun install --frozen-lockfile

# Convenience alias
bun ci

The flag fails with an error if package.json and bun.lock are out of sync. This prevents a CI build from silently resolving new versions or modifying the lockfile . The bun ci command is functionally identical and is the recommended form for CI pipelines .

The lockfile hash can be inspected for caching purposes. bun pm hash generates a hash from the lockfile, and bun pm hash-print prints the stored hash. This is useful for constructing CI cache keys that invalidate when dependencies change .


Complete Example Session

# ============================================
# PART 1: STANDARD INSTALL
# ============================================

bun install
# Writes bun.lock (v1.2+)
# Populates node_modules
# ============================================
# PART 2: INSPECT THE LOCKFILE
# ============================================

head -n 20 bun.lock
# JSONC format with dependency entries
# ============================================
# PART 3: LOCKFILE-ONLY
# ============================================

bun install --lockfile-only
# Writes bun.lock without installing packages
# ============================================
# PART 4: MIGRATE FROM BINARY
# ============================================

# If bun.lockb exists:
bun install --save-text-lockfile --frozen-lockfile --lockfile-only
rm bun.lockb
# bun.lock now exists and is used by future installs
# ============================================
# PART 5: CI INSTALL
# ============================================

bun install --frozen-lockfile
# Fails if package.json and lockfile disagree
# ============================================
# PART 6: CI ALIAS
# ============================================

bun ci
# Equivalent to bun install --frozen-lockfile
# ============================================
# PART 7: AUTOMATIC MIGRATION FROM NPM
# ============================================

# With package-lock.json present and no bun.lock:
bun install
# Migrates package-lock.json to bun.lock
# ============================================
# PART 8: LOCKFILE HASH
# ============================================

bun pm hash
# Prints the lockfile hash for CI caching

The eight parts trace the lockfile lifecycle: standard install, inspection, lockfile-only generation, binary migration, frozen install, CI alias, npm migration, and hash generation.


Quick Reference

Lockfile Formats

FormatFileDefault SinceReviewable
Textbun.lockv1.2Yes (JSONC)
Binarybun.lockbPre-v1.2No

Install Commands

CommandEffect
bun installInstall and write lockfile
bun install --lockfile-onlyWrite lockfile without installing
bun install --no-saveInstall without writing lockfile
bun install --frozen-lockfileFail if lockfile would change
bun ciAlias for --frozen-lockfile

Migration

TaskCommand
Binary to textbun install --save-text-lockfile --frozen-lockfile --lockfile-only
npm to Bunbun install (auto-migrates package-lock.json)
Yarn to Bunbun install (auto-migrates yarn.lock)

Best Practices

✅ Do This:

bun ci
<!-- Use the CI alias for frozen installs -->        # ✅
bun install --save-text-lockfile --frozen-lockfile --lockfile-only
<!-- Migrate from binary explicitly -->              # ✅
bun pm hash
<!-- Generate hash for CI cache keys -->             # ✅

❌ Don’t Do This:

# Assume bun install migrates bun.lockb automatically
<!-- Migration requires --save-text-lockfile -->     # ❌
# Commit both bun.lock and bun.lockb
<!-- Only one lockfile should be authoritative -->    # ❌
# Use --no-save in CI
<!-- Lockfile must be respected, not ignored -->      # ❌

Common Pitfalls

PitfallWhy It HappensFix
Lockfile not migratingNo --save-text-lockfile flagUse the migration command
CI fails with frozen lockfilepackage.json changed without lockfile updateRun bun install locally and commit lockfile
Both lockfiles presentMigration incompleteDelete bun.lockb after migration
Git cannot diff lockfileStill using bun.lockbMigrate to bun.lock
npm lockfile not migratingbun.lock already existsDelete bun.lock and re-run bun install

Real-World Examples

1. Standard Install

bun install

2. Lockfile-Only

bun install --lockfile-only

3. Migrate from Binary

bun install --save-text-lockfile --frozen-lockfile --lockfile-only
rm bun.lockb

4. CI Install

bun ci

5. Frozen Install

bun install --frozen-lockfile

6. Lockfile Hash

bun pm hash

7. Auto-Migrate npm

bun install
# package-lock.json → bun.lock

8. Auto-Migrate Yarn

bun install
# yarn.lock → bun.lock

9. Skip Lockfile

bun install --no-save

10. Inspect Lockfile

head -n 20 bun.lock

Visual

Lockfile Evolution

┌──────────────────────────────────────────────┐
│  Pre-v1.2                                    │
│                                              │
│  bun.lockb (binary)                          │
│  - Fast parse                                │
│  - Not diffable                              │
│  - Not mergeable                             │
└──────────────────┬───────────────────────────┘
                   │
                   │ Migration
                   ▼
┌──────────────────────────────────────────────┐
│  v1.2+                                       │
│                                              │
│  bun.lock (text, JSONC)                      │
│  - Diffable                                  │
│  - Mergeable                                 │
│  - 30% faster on warm cache                  │
└──────────────────────────────────────────────┘

CI Install Flow

┌──────────────────────────────────────────────┐
│  bun ci / bun install --frozen-lockfile      │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Lockfile matches package.json?              │
│  ├─ YES → Install exact versions             │
│  └─ NO  → FAIL                               │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  node_modules populated from lockfile        │
└──────────────────────────────────────────────┘

Summary

ItemValue
Default lockfile (v1.2+)bun.lock (text)
Legacy lockfilebun.lockb (binary)
Text formatJSONC
Cached install speed30% faster with text
CI flag--frozen-lockfile
CI aliasbun ci
Migration command--save-text-lockfile --frozen-lockfile --lockfile-only
Auto-migration sourcespackage-lock.json, yarn.lock, pnpm-lock.yaml

Key takeaways:

  • Bun v1.2 changed the default lockfile to text. bun.lock is reviewable, mergeable, and faster on warm caches than the old binary format .
  • The binary format is legacy, not removed. Existing bun.lockb files continue to work, but new projects and migrated projects use bun.lock .
  • Migration requires an explicit command. bun install does not automatically rewrite the lockfile format. The migration command uses the existing lockfile as the source of truth .
  • --frozen-lockfile is the CI safeguard. It prevents silent resolution changes and fails if package.json and the lockfile disagree. bun ci is the shorthand .
  • Bun auto-migrates from npm, Yarn, and pnpm. When no bun.lock exists, bun install reads the existing lockfile and produces a Bun lockfile .

Remember: The lockfile is the reproducibility contract. Bun’s move from binary to text was a recognition that reviewability matters as much as raw speed. Use bun.lock, commit it, and enforce it with bun ci. The binary format remains for legacy projects, but the text format is the standard.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!