环境变量与配置
本教程共 34 篇 · 第 7 篇 · 更新于 2026-08-06
本节目标:
- 理解 Bun 如何自动加载
.env以及多份文件的优先级- 搞清楚
Bun.env、import.meta.env与process.env是同一份数据的不同名字- 会用变量展开、引号与
--env-file/--no-env-file控制加载行为- 用
bunfig.toml管理项目级与全局配置(env、serve、install 等)
环境变量是配置程序最常用的手段:数据库密码、API Token、运行模式等都不该写死在代码里。Bun 在这块做了贴心的内置支持——你大概率不再需要 dotenv 这类包。这一节把机制讲透。
7.1 .env 自动加载与优先级
Bun 会自动读取当前目录下的 .env 系列文件,无需任何代码。按优先级从低到高(后者覆盖前者):
.env.env.production/.env.development/.env.test(取决于NODE_ENV的值).env.local
举例:用 NODE_ENV=production 运行时,.env.production 会覆盖 .env 里的同名项;设了 NODE_ENV=development 就用 .env.development。.env.local 排在最后,常被 git 忽略,用来放本机私有的覆盖值。
这样分层,你可以在仓库里提交一份通用的 .env,把环境专属值和敏感配置拆到别的文件里管理。
Warning有一个例外:
NODE_ENV=test时.env.local不会被加载。这是为了防止本机的私有覆盖污染测试环境,保证每次跑测试的环境一致。Next.js、Create React App 也是同样的约定。
# .env
FOO=hello
BAR=world
console.log(process.env.FOO); // "hello"
也可以在命令行直接设置变量:
# Linux / macOS
FOO=helloworld bun run dev
# Windows (CMD)
set FOO=helloworld && bun run dev
# Windows (PowerShell)
$env:FOO="helloworld"; bun run dev
Tip跨平台写变量,推荐用 Bun Shell,免去分平台语法的麻烦:
bun exec 'FOO=helloworld bun run dev'另外,在 Windows 上,
package.json脚本经bun run调用时会自动走 Bun Shell,所以脚本里写"dev": "NODE_ENV=development bun --watch app.ts"也是跨平台可用的。
也可以在代码里用 process.env.FOO = "hello" 赋值,效果等同于在运行时设置。
7.2 Bun.env / import.meta.env 是 process.env 的别名
三者指向同一份数据,读哪个都一样:
process.env.API_TOKEN; // "secret"
Bun.env.API_TOKEN; // "secret"
import.meta.env.API_TOKEN; // "secret"
Bun.env 与 import.meta.env 只是更「Bun 风格」的写法,方便在不能用 process 的上下文里取变量。import.meta.env 还常用于前端代码,便于和 Vite 等工具的习惯保持一致。
想一次性打印所有环境变量:
bun --print process.env
下面给一个最小可运行的完整示例,把「文件 → 读取 → 输出」串起来:
# .env
APP_NAME=MyApp
PORT=8080
// main.ts
console.log("app =", Bun.env.APP_NAME);
console.log("port =", Number(Bun.env.PORT));
bun run main.ts
# app = MyApp
# port = 8080
注意:.env 里的所有值都是字符串,使用时按需用 Number() / Boolean() 转换。不要把 "0" 当成 falsy——它是长度为一的非空字符串,在 JavaScript 里是 truthy,直接用 if (Bun.env.PORT) 做布尔判断可能得出与预期相反的结果。
Note当 Bun 以
node模式被调用时(例如bun --bun、bunx --bun,或一个指向 Bun 的node软链接),.env的自动加载会被关闭,以匹配 Node.js 的默认行为。这样像 Vite 的loadEnv这类自带.env解析逻辑的工具,才能正确选择对应模式的文件,而不被 Bun 预填的值干扰。如果你显式传了--env-file,则仍然会加载。
7.3 变量展开、引号与转义
.env 里支持双引号、单引号与模板字符串反引号:
FOO='hello'
FOO="hello"
FOO=`hello`
Bun 会自动展开变量,可以引用前面定义过的变量,适合拼连接字符串:
FOO=world
BAR=hello$FOO
process.env.BAR; // "helloworld"
构造数据库连接串时很好用:
DB_USER=postgres
DB_PASSWORD=secret
DB_HOST=localhost
DB_PORT=5432
DB_URL=postgres://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/app
若要原样保留 $ 而不展开,用反斜杠转义:
FOO=world
BAR=hello\$FOO
process.env.BAR; // "hello$FOO"
Note因为 Bun 原生读取
.env,所以dotenv与dotenv-expand在 Bun 项目里是多余的。如果你从 Node.js 老项目迁移并带了require("dotenv").config(),它在 Bun 下不会出错,但通常可以删掉,让 Bun 的自动加载接管。
7.4 手动指定与禁用 .env 加载
--env-file 可以精确指定要加载哪个(或哪几个).env 文件,覆盖默认加载:
bun --env-file=.env.1 src/index.ts
bun --env-file=.env.abc --env-file=.env.def run build
--no-env-file 则关闭自动加载,只认系统环境变量。这在不希望任何 .env 影响结果的场景(如生产、CI/CD)很有用:
bun run --no-env-file index.ts
Warning生产或 CI 环境里,如果敏感信息已经通过系统环境变量注入(如容器 secret、CI 变量),务必用
--no-env-file或bunfig.toml关掉.env自动加载,避免本地.env文件意外覆盖生产配置,或把开发用的假值带上线。注意:即便关掉默认加载,--env-file显式指定的文件仍然会加载。
7.5 在 TypeScript 里获得类型提示
默认 process.env 上每个属性都是 string | undefined。想要自动补全、并让某个变量被当作必填字符串,可以用接口合并(declaration merging):
declare module "bun" {
interface Env {
AWESOME: string;
}
}
把这个声明放进项目任意文件,全局就会给 process.env.AWESOME 与 Bun.env.AWESOME 加上 string 类型。
7.6 用 bunfig.toml 做项目配置
bunfig.toml 是 Bun 专属的配置文件(可选,没有它 Bun 也能跑)。Bun 尽量复用 package.json、tsconfig.json 等既有文件,bunfig.toml 只放 Bun 特有的设置。放在项目根目录(与 package.json 同级)即生效;全局配置可放在 $HOME/.bunfig.toml 或 $XDG_CONFIG_HOME/.bunfig.toml。若全局与本地都存在,则浅合并,本地优先;CLI 参数优先级最高。
最常用的几个字段:
关闭 .env 自动加载
# 关闭默认 .env 加载(生产 / CI 推荐)
env = false
也支持对象写法:
[env]
file = false
配置 HTTP 服务默认端口
[serve]
port = 3000
也可通过 BUN_PORT / PORT 环境变量或 --port 覆盖。
设置运行时日志级别
logLevel = "warn" # "debug" | "warn" | "error"
配置 JSX(非 TS 项目也能用)
jsx = "react"
jsxFactory = "h"
jsxImportSource = "react"
关闭遥测与崩溃报告
telemetry = false
等价于设置环境变量 DO_NOT_TRACK=1。
指定预加载脚本
# 运行任何文件或脚本前先执行
preload = ["./preload.ts"]
Tip还有大量
[install]、[test]、[run]子配置可写进bunfig.toml,例如指定私有 registry、锁文件冻结(frozenLockfile)、测试覆盖率阈值、把node透明替换成bun(run.bun = true)等。它们属于包管理器与测试章节的内容,这里先知道「bunfig.toml 是统一配置入口」即可,用到再查对应章节。
举两个会在后续章节深入、但此处可先建立印象的例子:
# CI 里锁定依赖版本,不更新 bun.lock
[install]
frozenLockfile = true
# 让 bun run 起的服务默认走 Bun(node 透明替换)
[run]
bun = true
优先级始终是:CLI 参数 > 本地 bunfig.toml > 全局 .bunfig.toml。因此团队成员可以把个人偏好放全局配置,项目统一约束放本地配置,命令行临时覆盖,三者各司其职、互不打架。
7.7 几个有用的 Bun 专属环境变量
除了读你自己的变量,Bun 也认一些控制自身行为的变量:
| 变量 | 作用 |
|---|---|
NODE_TLS_REJECT_UNAUTHORIZED=0 | 关闭 SSL 证书校验,仅调试用,生产慎用 |
BUN_CONFIG_VERBOSE_FETCH=curl | 把 fetch 请求的 URL / 头打印成 curl 形式,便于调试 |
BUN_CONFIG_MAX_HTTP_REQUESTS | fetch 与 bun install 的最大并发请求数,默认 256 |
BUN_OPTIONS="--hot" | 给任意 Bun 执行追加 CLI 参数,等价于默认带上 --hot |
DO_NOT_TRACK=1 | 关闭崩溃报告与遥测上传 |
NO_COLOR=1 / FORCE_COLOR=1 | 控制是否输出 ANSI 颜色 |
例如想让所有 bun run 默认带热重载:
BUN_OPTIONS="--hot" bun run dev
7.8 小结
- Bun 自动加载
.env系列文件,优先级:.env<.env.{mode}<.env.local;NODE_ENV=test时不加载.env.local。 Bun.env、import.meta.env、process.env是同一份数据的三个名字。- 变量支持引号与
$展开;\$转义可阻止展开。原生支持让你无需dotenv。 --env-file指定文件,--no-env-file关闭自动加载(生产 / CI 推荐)。bunfig.toml是 Bun 专属配置入口,可关.env、设端口、配 JSX、管 install/test/run;本地覆盖全局,CLI 覆盖配置。
Note配置这件事,「显式优于隐式」。在团队项目里,建议把
.env.local放进.gitignore,只提交.env.example作为模板;生产变量走系统环境变量并配合--no-env-file,这样配置来源清晰、不易出错。同时记住:.env不会被 Bun 自动提交到任何地方,但本地明文密码仍要当心,分享机器或做容器镜像前先确认没有把含密钥的.env一并打进去。