首页 / Bun 入门教程 / bun install 入门

Bun 入门教程

bun install 入门

本教程共 34 篇 · 第 11 篇 · 更新于 2026-08-06

Bunbun install包管理器依赖安装bun addbun removebunxnpm 兼容

本节目标:

  • 理解 bun install 的定位:它是 Bun 内置、与 Node.js 项目兼容的包管理器,可直接替换 npm/yarn/pnpm
  • 掌握 bun installbun addbun removebunx 的常用命令与等价写法。
  • 了解 Bun 在依赖安装上的两个关键取向——速度默认安全(不执行依赖的生命周期脚本)。
  • 会用 --production--frozen-lockfile 等标志做可复现安装,并理解非 npm 来源(Git、tarball、全局)依赖。

11.1 Bun 内置的包管理器

Bun 不只是一个运行时,它还内置了一套 npm 兼容的包管理器。只要你的项目里有 package.json,无论原本用的是 npm、yarn 还是 pnpm,都可以直接在项目根目录运行:

bun install

这条命令会读取 package.json 中的 dependenciesdevDependenciesoptionalDependenciespeerDependencies,把它们安装到 node_modules,并写入一份 bun.lock 锁文件。也就是说,你不需要为了用 Bun 而迁移整个工程——很多团队是先拿 bun install 替换 npm install,体验更快的安装速度,再逐步把 bun runbun test 也用起来。

Note

官方文档给出的对比数据是:把任意 Node.js 项目里的 npm install 换成 bun install,安装速度最高可快约 25 倍。这个差异主要来自 Bun 在依赖解析、缓存与文件拷贝(hardlink / clonefile)层面的工程优化,而非某一个单独的”黑科技”。

11.2 安装全部依赖

最基础的用法就是不带任何参数:

bun install

执行时,Bun 会做三件事:

  1. 安装 dependenciesdevDependenciesoptionalDependenciespeerDependencies 默认也会一并安装(行为更接近 Yarn)。
  2. 运行自己项目{pre|post}install{pre|post}prepare 脚本。
  3. 写入 bun.lock 锁文件到项目根目录。

需要留意的是第二点里的”安全边界”:Bun 不会执行已安装依赖包里的 {pre|post}install 等生命周期脚本。这是 Bun 有意设计的默认安全策略(详见第 14 章”生命周期脚本”),目的是降低供应链攻击面。如果你确实需要一个依赖运行它的 postinstall(例如 sharpesbuild 这类需要下载平台二进制文件的包),需要把它加入 trustedDependencies(第 14 章会展开)。

第一次跑完之后再执行一次 bun install,你会发现它几乎瞬间返回。原因在于 Bun 会先比对 package.jsonbun.lock 是否仍然吻合:吻合就直接进入”校验并补齐缺失文件”的快路径,不再向 registry 重新请求版本信息;只有当你改了依赖声明、或锁文件根本不存在时,才会触发完整的解析流程。理解这一点很有用——如果你发现每次安装都很慢,通常不是网络问题,而是锁文件没有被正确复用,比如它被误加进了 .gitignore,或者 CI 每次都在一个干净目录里从头解析。

调高或调低日志输出也很简单:

bun install --verbose  # 输出调试日志
bun install --silent   # 不输出日志

--verbose 在排查”某个包为什么解析到了这个版本”时特别有价值:它会打印出每一步的请求与命中缓存的情况,比盯着最终的 node_modules 反推要直接得多。

11.3 添加与移除依赖:bun add / bun remove

添加依赖用 bun add,它等价于 npm install <pkg>

bun add preact                 # 添加到 dependencies
bun add zod@3.20.0             # 指定精确版本
bun add zod@^3.0.0             # 指定版本范围
bun add zod@latest             # 指定 tag(latest)

把它加为开发依赖、可选依赖或 peer 依赖,对应不同的标志:

bun add --dev @types/react     # 等价 --development / -d / -D,写入 devDependencies
bun add --optional lodash      # 写入 optionalDependencies
bun add --peer @types/bun      # 写入 peerDependencies
bun add react --exact          # 等价 -E,写入精确版本而非范围

--exact(或 -E)的区别很直观:不加时 package.json 里写的是 "react": "^18.2.0"(匹配 >=18.2.0 <19.0.0);加上后写的是 "react": "18.2.0",只锁定这一个版本。

移除依赖则是 bun remove,等价于 npm uninstall

bun remove ts-node
Tip

bun addbun remove 都会同步更新 package.jsonbun.lock。需要查看当前支持的全部选项时,运行 bun add --help 即可。

11.4 运行一次性命令:bunx

bunxbun x 的别名,相当于 npxyarn dlx:它会优先查找本地已安装的包,找不到时再从 npm 自动下载并运行。安装 Bun 时 bunx 会一并可用。

bunx cowsay "Hello world!"

很多 CLI 工具在 package.json"bin" 字段里声明可执行文件。你可以用 bunx 直接调用它们;如果可执行文件名和包名不一致,用 -p / --package 指定包:

bunx --package @angular/cli ng      # 指定从 @angular/cli 运行 ng
bunx -p renovate renovate-config-validator

默认情况下,bunx 会尊重可执行文件里的 shebang。如果某个文件写了 #!/usr/bin/env node,Bun 会启动一个 node 进程来跑它;想改用 Bun 运行时执行,加 --bun 标志(注意它要放在可执行文件名之前):

bunx --bun my-cli        # 用 Bun 运行
bunx my-cli --bun        # 错误:--bun 会被当作 my-cli 的参数
Note

官方文档称,由于 Bun 启动极快,bunx 运行本地已安装包时大约比 npx100 倍。跨平台下载的包会进入 Bun 的全局缓存(见第 14 章),再次运行无需重复下载。

11.5 生产模式与可复现安装

在 CI / 生产环境,你通常希望只装 dependencies 并得到完全确定的结果:

bun install --production          # 不安装 devDependencies
bun install --frozen-lockfile     # 严格按照 bun.lock 安装,不更新锁文件

--frozen-lockfile 的含义是:完全按锁文件里的版本安装;如果 package.jsonbun.lock 不一致,Bun 会直接报错退出,而不是悄悄修改锁文件。这正是”可复现构建”想要的严格行为。

Warning

使用 --frozen-lockfile(或等价的 bun ci,见第 15 章)时,必须先把 bun.lock 提交到版本库。否则锁文件缺失,Bun 无法做冻结安装。

还有一个容易被忽略的细节:Bun 会检测 CI 环境。当环境变量 CI=true 时,bun install 会自动启用冻结行为,效果等同于显式加了 --frozen-lockfile。也就是说在 GitHub Actions、GitLab CI 这类默认设置了 CI 变量的平台上,即便你什么标志都没写,package.json 与锁文件不一致同样会让构建失败。这个默认值是好事——它把”悄悄改锁文件”这条路堵死了。反过来,如果某个流水线确实需要更新锁文件(比如一个专门用来升级依赖、然后自动开 PR 的定时任务),就要显式加 --no-frozen-lockfile 把它关掉。

你也可以用 --omit 精细排除某一类依赖:

bun install --omit dev            # 排除 devDependencies
bun install --omit=dev --omit=peer --omit=optional

想先”演习”一遍、看看会发生什么而不真正安装,加 --dry-run 即可。

11.6 全局安装

和 npm 一样,Bun 支持全局安装命令行工具(不会修改当前项目的 package.json):

bun install --global cowsay       # 等价 bun install -g / bun add -g cowsay
cowsay "Bun!"

全局包与它们的可执行文件分别落在 ~/.bun/install/global~/.bun/bin,可在 bunfig.toml 里通过 install.globalDir / install.globalBinDir 配置。

11.7 非 npm 来源的依赖

除了从 npm registry 安装,Bun 也支持 Git、GitHub 以及本地/远程 tarball 作为依赖来源。直接写进 package.json 即可:

{
  "dependencies": {
    "dayjs": "git+https://github.com/iamkun/dayjs.git",
    "lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21",
    "zod": "github:colinhacks/zod",
    "react": "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
  }
}

也可以用 bun add 一步写好:

bun add git@github.com:moment/moment.git
bun add zod@https://registry.npmjs.org/zod/-/zod-3.21.4.tgz

11.8 安装策略:hoisted 与 isolated

Bun 支持两种 node_modules 组织方式,通过 --linker 控制:

bun install --linker hoisted     # 传统平铺,类似 npm/Yarn
bun install --linker isolated    # 严格隔离,类似 pnpm,杜绝"幽灵依赖"

默认策略取决于场景:新建的单包项目hoisted(贴近 npm 习惯),新建的工作区/monorepoisolated(防止未声明却能引用的”幽灵依赖”),旧项目则保留 hoisted 以保证向后兼容。相关细节会在第 13、14 章深入。

Tip

想要更可控的安装行为(是否装 dev/optional、并发脚本数、默认 linker 等),把这些配置写进 bunfig.toml[install] 段即可,免得每次都在命令行加一长串标志。

11.9 常见问题速答

Q:bun installbun i 有区别吗?

没有区别。bun ibun install 的官方简写,两者行为完全一致。类似地,bun add --dev 也可以写成 -d-D--development,挑顺手的用即可,不必纠结。

Q:装完之后,为什么代码里 import 一个没在 package.json 里声明过的包会失败?

如果当前用的是 isolated 策略(新建工作区项目的默认值),只有显式声明过的依赖才对你可见——这正是它的设计意图,用来杜绝”幽灵依赖”。这类报错其实是在帮你提前发现问题:把缺失的包用 bun add 正式加进来,远比切回 hoisted 掩盖问题要稳妥。

Q:能不能只用 Bun 装依赖,仍然用 Node.js 跑代码?

完全可以,而且这是引入 Bun 风险最低的方式。bun install 生成的是标准的 node_modules 目录结构,Node.js 可以直接读取,不需要任何额外适配。很多团队的第一步就是只把 Bun 当”更快的 npm”,运行时继续用 Node.js,跑顺了再考虑后面的事。

Q:bunxbun run 该怎么选?

bun run <script> 执行的是 package.jsonscripts 字段定义的脚本;bunx <pkg> 执行的是某个包提供的可执行文件,本地没装时会临时下载。日常的构建、测试、启动用前者;临时用一次某个脚手架或校验工具(比如生成一个项目模板)用后者。

Q:安装报错说某个原生包缺二进制文件,怎么办?

这几乎总是因为它的 postinstall 被默认拦截了。先用 bun pm untrusted 看看哪些包的脚本被拦下来,确认来源可信后再用 bun pm trust <name> 放行,或者直接写进 package.jsontrustedDependencies。第 14 章会完整讲这套机制。

11.10 小结

  • bun install 是 Bun 内置、npm 兼容的包管理器,可直接用于既有 Node.js 项目,安装速度明显更快。
  • 日常增删依赖用 bun add / bun remove;运行一次性 CLI 用 bunx
  • Bun 默认不执行依赖包的生命周期脚本,需要时用 trustedDependencies 放行——这是一项安全取舍,而非缺陷。
  • 生产/CI 用 --production--frozen-lockfilebun ci)保证可复现;Git、tarball、全局安装等非标准来源也都受支持。

下一章我们会专门聊 bun.lock 这份锁文件:它为什么是文本格式、相比旧的二进制 bun.lockb 好在哪里、以及迁移方法。