All-in-one JavaScript/TypeScript toolkit: fast runtime, package manager, test runner, and bundler. Version-aware skill backed by the ask CLI.
75
94%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
Drop-in replacement for npm/yarn/pnpm. Reads package.json, writes bun.lock (text JSONC; the default lockfile format since Bun 1.2.0).
bun install # install all deps; alias: bun i
bun add react # add to dependencies
bun add -d @types/bun # devDependencies; aliases: --development, --save-dev
bun add -o sharp # optionalDependencies
bun add -p react # peerDependencies (also installed by default)
bun add react@19.1.1 # exact
bun add react@latest # tag
bun add github:vercel/next.js # git
bun add ./local-pkg # tarball or local path
bun remove react # alias: bun rm
bun update # update within ranges; rewrites lockfile
bun outdated # show outdated packages
bun audit # security advisories (1.2+)
bun pm ls # list installed
bun pm trust <pkg> # allow lifecycle scripts (postinstall, etc.)
bun pm untrusted # list pkgs blocked from running lifecycle scripts
bun pm cache # show cache dir
bun pm cache rm # purge cache
bun pm migrate # migrate from npm/yarn/pnpm lockfile
bun pm pack # create publishable tarball (resolves workspace:*/catalog:)
bun publish # publish to registryUnlike npm, Bun does not execute postinstall/preinstall/prepublish scripts of installed dependencies by default. Allowlist what you trust:
{
"trustedDependencies": ["sharp", "esbuild", "puppeteer"]
}Your own project's scripts (scripts.preinstall, etc.) always run. The block applies only to third-party dependencies.
{
"name": "my-monorepo",
"private": true,
"workspaces": ["packages/*", "apps/*", "!packages/**/template/**"],
"devDependencies": {
"shared-utils": "workspace:*"
}
}Glob syntax (including negation) is supported. Inside a workspace package reference others by:
{ "dependencies": { "pkg-b": "workspace:*" } }On publish, bun pm pack and bun publish rewrite workspace:* to the current version. Filter operations:
bun install --filter "pkg-*" --filter "!pkg-c"
bun run --filter "./apps/web" dev
bun run --filter "*" buildShare dependency versions across a monorepo from one place:
{
"workspaces": {
"packages": ["packages/*"],
"catalog": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"catalogs": {
"testing": {
"jest": "30.0.0"
}
}
}
}{
"dependencies": {
"react": "catalog:", // default catalog
"react-dom": "catalog:",
"jest": "catalog:testing" // named catalog
}
}bun pm pack / bun publish resolves catalog: to the concrete version.
Force a specific version of a transitive dependency:
{
"overrides": {
"lodash": "4.17.21",
"react": "$react" // alias the value of root react
}
}overrides is the standard npm-compatible spelling. Bun also recognises resolutions (Yarn-style) for compatibility.
Strict, pnpm-style symlinked node_modules that prevents phantom dependencies:
[install]
linker = "isolated"Default is hoisted (npm-style). Switch to isolated for strict resolution; expect to declare every dependency you import.
[install.registry]
default = "https://npm.example.com/"
[install.scopes]
"@my-org" = { url = "https://npm.pkg.github.com/", token = "$GITHUB_TOKEN" }Or via .npmrc (Bun reads it for compatibility):
@my-org:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}Tokens can reference env vars with $VAR.
[install]
optional = true # install optionalDependencies
dev = true # install devDependencies
peer = true # install peerDependencies (Bun does this by default)
production = false # set true in CI / Docker to skip dev deps
exact = false # write exact versions (no ^ or ~) on bun add
saveTextLockfile = true # default since 1.2.0
linker = "hoisted" # or "isolated"
frozenLockfile = false # true in CI
[install.cache]
dir = "~/.bun/install/cache"
disable = false
disableManifest = false# Lock the lockfile in CI — fail if it would change
bun install --frozen-lockfile
# Production install (skip devDeps)
bun install --production
# Reuse cache between jobs
# GitHub Actions:
# uses: oven-sh/setup-bun@v2
# with: { bun-version: latest }
# cache key: hash of bun.lock; cache path: ~/.bun/install/cache| From | Command |
|---|---|
package-lock.json (npm) | bun install — auto-imports |
yarn.lock (Yarn) | bun install — auto-imports |
pnpm-lock.yaml (pnpm) | bun pm migrate then bun install |
After migration, commit bun.lock and remove the old lockfile to avoid drift.
bun.lock is text JSONC, reviewable in diffs. The old bun.lockb is binary — if you still see it, run bun install once to regenerate as text, then delete bun.lockb.workspace: not on disk: workspace: paths are resolved by Bun, not by node_modules symlinks (default linker is hoisted). If you need a symlinked tree, set linker = "isolated".sharp, better-sqlite3) that look broken because their postinstall didn't run. Check bun pm untrusted and add to trustedDependencies.catalog: resolution at publish: bun publish / bun pm pack rewrite the protocol; consumers see the concrete version. Do not write catalog: references manually outside a monorepo root.