Skip to content

/commands/bun/bun-add

bun add: install a package with Bun (dev, exact, global)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
Bun
versions
Bun 1.2+
os
linux, macos, windows

bun add express adds a package to the dependencies of package.json, installs it into node_modules and updates the bun.lock lockfile, the Bun equivalent of npm install express. Add -d (--dev) for devDependencies, --exact to save the version without a caret, and -g to install a command-line tool globally.

Add a dependency and a dev dependency

bash
export NO_COLOR=1
echo '{ "name": "app", "private": true }' > package.json
npx --yes bun@1 add is-odd@3.0.1 2>&1 | grep -E "^installed"
npx --yes bun@1 add -d --exact is-number@7.0.0 2>&1 | grep -E "^installed"
cat package.json
ls bun.lock node_modules/is-odd/package.json

Output

installed is-odd@3.0.1
installed is-number@7.0.0
{
  "name": "app",
  "private": true,
  "dependencies": {
    "is-odd": "3.0.1"
  },
  "devDependencies": {
    "is-number": "7.0.0"
  }
}
bun.lock
node_modules/is-odd/package.json

Bun prints one installed line per package you asked for, writes bun.lock (a text lockfile; Bun 1.1 and older wrote the binary bun.lockb) and creates node_modules. The example starts Bun through npx bun@1 so it needs only Node.js; with Bun installed the commands are bun add is-odd@3.0.1 and bun add -d --exact is-number@7.0.0.

Variants

CommandWhat it does
bun add reactLatest version, saved as a caret range (^x.y.z)
bun add react@18.3.1A specific version
bun add react@nextA dist-tag
bun add -d typescriptdevDependencies (long form --dev)
bun add --exact zodSave the exact version instead of a range (-E)
bun add --optional sharpoptionalDependencies
bun add --peer reactpeerDependencies
bun add --trust esbuildAdd the package and allow its lifecycle scripts (trustedDependencies)
bun add -g serveInstall a CLI globally (into ~/.bun/bin by default)
bun add github:user/repoA Git dependency; git+https and tarball URLs also work
bun remove is-oddRemove the package from package.json, node_modules and bun.lock

Defaults and pitfalls

  • Ranges. Without a version, Bun saves a caret range like npm does; an exact version you type (is-odd@3.0.1) is saved as written, as the example shows. Set exact = true under [install] in bunfig.toml to save exact versions by default.
  • Lifecycle scripts. Dependencies' postinstall scripts are not run unless the package is listed in trustedDependencies; packages that build native code may look installed but not work until you trust them.
  • Version not found. A version or tag that does not exist fails with No version matching found for specifier; check the published versions with bun info pkg or npm view pkg versions.
  • CI. Use bun install --frozen-lockfile in CI, not bun add. It fails with lockfile had changes, but lockfile is frozen when package.json and bun.lock disagree.
  • Workspaces. In a monorepo, run bun add inside the package folder, or use --filter, to add the dependency to that package rather than to the root.

How to confirm it worked

cat package.json shows the new entry in the right section, bun pm ls lists the installed top-level packages with their versions, and ls node_modules/PACKAGE shows that it is on disk. Running bun install again without changes should report that nothing needs to be installed.

FAQ

What is the difference between bun add and bun install?

bun add pkg adds a new dependency to package.json and installs it. bun install with no package name installs everything already listed in package.json and the lockfile, for example after a fresh clone.

Does bun add work with an existing package-lock.json?

Yes. When a project has no bun.lock yet, Bun can read package-lock.json or yarn.lock to keep the versions you already use, then writes its own bun.lock. Commit bun.lock once the project uses Bun.

Why does bun add not run the postinstall script of a package?

Bun does not run lifecycle scripts of dependencies by default, for security. List packages you trust in trustedDependencies in package.json, or run bun pm trust package, to allow their scripts.

Sources