bun pm
Package manager utilities
The bun pm command group is a set of utilities for working with Bun's package manager.
pack#
To create a tarball of the current workspace:
bun pm packbun pm pack creates a .tgz file containing all files that would be published to npm, following the same rules as npm pack.
Examples#
Basic usage:
bun pm pack
# Creates my-package-1.0.0.tgz in current directoryQuiet mode for scripting:
TARBALL=$(bun pm pack --quiet)
echo "Created: $TARBALL"Created: my-package-1.0.0.tgzCustom destination:
bun pm pack --destination ./dist
# Saves tarball in ./dist/ directoryOptions#
--dry-run: Perform all tasks except writing the tarball to disk. Shows what would be included.--destination <dir>: The directory to save the tarball in.--filename <name>: An exact file name for the tarball.--ignore-scripts: Skip running pre/postpack and prepare scripts.--gzip-level <0-9>: Set the gzip compression level, from 0 to 9 (default 9).--quiet: Print only the tarball filename, suppressing the rest of the output. Useful in scripts.
Note:
--filenameand--destinationcannot be used at the same time.
Output Modes#
Default output:
bun pm packbun pack v1.2.19
packed 131B package.json
packed 40B index.js
my-package-1.0.0.tgz
Total files: 2
Shasum: f2451d6eb1e818f500a791d9aace80b394258a90
Unpacked size: 171B
Packed size: 249BQuiet output:
bun pm pack --quietmy-package-1.0.0.tgzbin#
To print the path to the bin directory for the local project:
bun pm bin/path/to/current/project/node_modules/.binTo print the path to the global bin directory:
bun pm bin -g<$HOME>/.bun/binls#
To print a list of installed dependencies in the current project and their resolved versions, excluding their dependencies:
bun pm ls
# or
bun list/path/to/project node_modules (135 installed)
├── eslint@8.38.0
├── react@18.2.0
├── react-dom@18.2.0
├── typescript@5.0.4
└── zod@3.21.4To print all installed dependencies, including nth-order dependencies:
bun pm ls --all
# or
bun list --all/path/to/project node_modules (135 installed)
├── @eslint-community/eslint-utils@4.4.0
├── @eslint-community/regexpp@4.5.0
├── @eslint/eslintrc@2.0.2
├── @eslint/js@8.38.0
├── @nodelib/fs.scandir@2.1.5
├── @nodelib/fs.stat@2.0.5
├── @nodelib/fs.walk@1.2.8
├── acorn@8.8.2
├── acorn-jsx@5.3.2
├── ajv@6.12.6
├── ansi-regex@5.0.1
├── ...To print only trusted dependencies (those allowed to run lifecycle scripts). When trustedDependencies is set in package.json, Bun shows the packages from that list; otherwise it shows packages from its default trusted dependencies list.
bun pm ls --trusted
# or
bun list --trusted/path/to/project node_modules (135 installed)
└── esbuild@0.21.5licenses#
List every installed package grouped by license, as read from each package's package.json in node_modules. Bun lists packages without a license field under Unknown. Bun marks packages only reachable through devDependencies with (dev).
bun pm licenses
# or
bun pm licenses lsbun pm licenses v1.3.0 (a4b2f86f)
MIT (2)
├── path-parse@1.0.6
└── resolve@1.9.0
Unknown (4)
├── a-dep@1.0.1 (dev)
├── no-deps@1.0.0
├── no-deps@1.0.1
└── one-dep@1.0.0
6 packages across 2 licenses (checked 6 packages in bun.lock) [4.00ms]| Flag | Description |
|---|---|
--json | Print a JSON object keyed by license |
--long | Also print each package's author, description, and homepage |
--prod, -p | Skip devDependencies (same as --omit=dev) |
--dev, -D | Only list what devDependencies pull in |
--omit=<dev|optional|peer> | Skip a dependency type, as with bun install |
--filter <pattern>, -F | Only list dependencies of the matching workspaces (filter syntax) |
bun pm licenses --json --prod{
"MIT": [
{
"name": "path-parse",
"versions": ["1.0.6"],
"paths": ["/home/me/app/node_modules/path-parse"],
"license": "MIT",
"homepage": "https://github.com/jbgutierrez/path-parse#readme",
"author": "Javier Blanco <http://jbgutierrez.info>",
"description": "Node.js path.parse() ponyfill"
}
]
}From a workspace root, Bun lists every workspace's dependencies. From inside a workspace package, Bun lists only that package's dependencies. Use bun why to find out what pulls in an unexpected package.
Requires both bun.lock and node_modules. Bun skips packages that are in the lockfile but missing from node_modules (e.g. after bun install --production) and prints a warning.
diff#
Show what changed between two versions of a package: a summary of the files and lines touched, the package.json changes worth a second look (new install scripts, dependencies, entry points, binaries), then a unified diff of every file. Each side can be a registry spec, a local folder, or a .tgz.
bun pm diff react # the version in bun.lock → latest
bun pm diff react@18.2.0 19.0.0 # two published versions
bun pm diff react@18.2.0..19.0.0 # same thing
bun pm diff ./vendored-pkg pkg@2.1.0 # a folder against a published version
bun pm diff # in a package folder: what is published → this folderis-number@6.0.0 → is-number@7.0.0
4 files changed, 0 added, 0 removed (+73 -44 lines)
! engines changed: { "node": ">=0.10.0" } → { "node": ">=0.12.0" }
diff --bun a/index.js b/index.js
--- a/index.js
+++ b/index.js
@@ -9,10 +9,10 @@
module.exports = function(num) {
if (typeof num === 'number') {
- return num - num === 0;
+ return num - num === 0;
}
...On a terminal, code is compared by meaning and shown as written. Both sides of every .js/.mjs/.cjs/.jsx/.ts/.tsx file are parsed and re-printed in one canonical form (equivalent syntax folded, unreachable code dropped); that canonical form decides what changed, and the hunks show the original lines — comments, types, JSX and names intact:
1 + 1vs2,'a'vs"a",!0vstrue, a re-wrapped call, a whole-file reformat, or a local renamed consistently everywhere (a bundler'sutils→utils$1) are not changes — locals on both sides are matched by how they are used, never by what they are called. Lines folded away this way are counted in the file header (3 folded), and a file with nothing left readsformatting only.- A comment edit, a changed type annotation, or any change in control flow is a change, shown in the author's words.
- Unchanged text whose meaning moved — code that became unreachable, or dead code that came alive because a condition elsewhere flipped — is marked
~. - Minified bundles have no readable original, so an un-minified re-print stands in for it (one declaration, call and property per line, each numbered by its
line:colin the original) and the same folded comparison decides what changed — with the short names two builds' minifiers handed out differently renamed in lockstep;dist/*.min.jsdiffs down to the lines that actually changed rather than one enormous-/+pair..jsonand.cssfiles are compared and shown as their canonical print (normalized), so a reformat around one edit is one edit; identical prints readformatting only. - The summary at the end calls out what a reviewer looks for first: new
install/postinstallscripts, dependency and entry-point changes, a file that newly importschild_process/fs/net/http/vm/…, new package imports, growth ineval()/new Function()/process.env/fetch()use, newly executable files, and terminal escape sequences or bidirectional-text controls appearing in a release.*.mapfiles are summarised as regenerated rather than shown. Files over 64 MB are diffed as text (too large to normalize). - Line tints follow the terminal: light or dark is taken from
COLORFGBGor by asking the terminal for its background colour (OSC 11), and exact colours are used whenCOLORTERM=truecolor. - Nothing in a package can drive your terminal: control characters, escape sequences and bidirectional-text overrides in file contents are drawn as
␛,^M,‹U+202E›. Permission changes show asmode 644 → 755/new file mode 100755.
To look at part of a package, name the files: as a :path suffix on a spec, as a bare :path argument, or as extra arguments after the two sides. A path matches a file exactly, a directory, a file name anywhere in the package, or a glob:
bun pm diff axios@1.6.0:lib/adapters 1.6.1 # one directorybun pm diff axios@1.6.0 axios@1.6.1 dist/node/axios.cjs README.mdbun pm diff lodash :trimEnd.js # installed → latest, one filebun pm diff react-dom@18.2.0 18.3.1 '*.min.js'bun pm diff react-dom@18.2.0 18.3.1 'cjs/**/*.production.min.js'A local folder that has a package.json is read the way bun pm pack would publish it — the files field, .npmignore / .gitignore, bin — so diffing a checkout against the registry compares what would ship, not node_modules/, vendor/ or build output.
Piped or with NO_COLOR, the output is a plain unified patch of the real file contents (so bun pm diff a b > changes.patch applies), and --raw turns the re-print off on a terminal too.
| Flag | Description |
|---|---|
--raw, --unformatted | Compare bytes as-is; skip the JS/CSS/JSON re-print |
--minify | Also fold equivalent syntax (!0/true, quote style, redundant parens) so only meaning is compared |
--unminify | Rename short locals in lockstep in every JS file, not just ones that look minified |
-w, --ignore-space | On a terminal, show files that differ only in whitespace as whitespace only instead of hunks |
--stat | One line per file with a change count and bar instead of the hunks |
--name-only | Only list the files that differ, marked Added / Modified / Deleted |
-U <n>, --unified | Lines of context around each change (default 3) |
--diff <spec> | npm-compatible way to name a side; may be given twice |
--json | One JSON document: from/to, per-file status/counts/patch, plain-text notes, and totals |
With one name and no version, the left side is the version this project's bun.lock resolved and the right side is latest, so bun pm diff <pkg> answers "what would updating this pull in?". Registry, scope and auth settings come from bunfig.toml / .npmrc as for bun install; outside a project only registry specs and absolute or ./ paths are accepted.
whoami#
Print your npm username. Requires you to be logged in (bunx npm login) with credentials in either bunfig.toml or .npmrc:
bun pm whoamihash#
To generate and print the hash of the current lockfile:
bun pm hashTo print the string used to hash the lockfile:
bun pm hash-stringTo print the hash stored in the current lockfile:
bun pm hash-printcache#
To print the path to Bun's global module cache:
bun pm cacheTo clear Bun's global module cache:
bun pm cache rmmigrate#
To migrate another package manager's lockfile without installing anything:
bun pm migrateuntrusted#
To print current untrusted dependencies with scripts:
bun pm untrusted./node_modules/@biomejs/biome @1.8.3
» [postinstall]: node scripts/postinstall.js
These dependencies had their lifecycle scripts blocked during install.trust#
To run scripts for untrusted dependencies and add to trustedDependencies:
bun pm trust <names>Options for the trust command:
--all: Trust all untrusted dependencies.
default-trusted#
To print the default trusted dependencies list:
bun pm default-trustedSee the current list on GitHub.
version#
To display current package version and help:
bun pm versionbun pm version v1.3.3 (ca7428e9)
Current package version: v1.0.0
Increment:
patch 1.0.0 → 1.0.1
minor 1.0.0 → 1.1.0
major 1.0.0 → 2.0.0
prerelease 1.0.0 → 1.0.1-0
prepatch 1.0.0 → 1.0.1-0
preminor 1.0.0 → 1.1.0-0
premajor 1.0.0 → 2.0.0-0
from-git Use version from latest git tag
1.2.3 Set specific version
Options:
--no-git-tag-version Skip git operations
--allow-same-version Prevents throwing error if version is the same
--message=<val>, -m Custom commit message, use %s for version substitution
--preid=<val> Prerelease identifier (i.e beta → 1.0.1-beta.0)
--force, -f Bypass dirty git history check
Examples:
bun pm version patch
bun pm version 1.2.3 --no-git-tag-version
bun pm version prerelease --preid beta --message "Release beta: %s"To bump the version in package.json:
bun pm version patchv1.0.1Supports patch, minor, major, premajor, preminor, prepatch, prerelease, from-git, or specific versions like 1.2.3. By default it creates a git commit and tag; pass --no-git-tag-version to skip them.
pkg#
Manage package.json data with get, set, delete, and fix operations.
All commands support dot and bracket notation:
scripts.build # dot notation
contributors[0] # array access
workspaces.0 # dot with numeric index
scripts[test:watch] # bracket for special charsExamples:
# get
bun pm pkg get name # single property
bun pm pkg get name version # multiple properties
bun pm pkg get # entire package.json
bun pm pkg get scripts.build # nested property
# set
bun pm pkg set name="my-package" # simple property
bun pm pkg set scripts.test="jest" version=2.0.0 # multiple properties
bun pm pkg set private=true --json # JSON values with --json flag
# delete
bun pm pkg delete description # single property
bun pm pkg delete scripts.test contributors[0] # multiple/nested
# fix
bun pm pkg fix # auto-fix common issues