Menu

Node.js process.env:读取环境变量

process.env 是一个对象,保存着 Node.js 程序启动时拿到的环境变量。每个值要么是字符串,要么是 undefined,所以数字和布尔值需要你自己转换,并且每个变量都应该有默认值。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

process.env 是一个对象,shell 传给 Node.js 程序的每个环境变量都是它的一个属性:process.env.PORT、process.env.DATABASE_URL 等等。没有设置的变量读出来是 undefined,设置过的变量永远是字符串。在启动时读取一次,给它一个默认值,再转换成你需要的类型。

它打印了 shop on port 8080 in eu-west(REGION 从未设置,所以用了默认值),然后是 string number:变量在被 Number() 转换之前一直是文本。删掉前两行赋值再运行一次,就能看到所有默认值。

在 shell 中设置环境变量

变量来自启动 Node.js 的地方。在终端里:

// macOS and Linux: for one command
PORT=8080 NODE_ENV=production node app.js

// macOS and Linux: for the rest of the terminal session
export PORT=8080

// Windows PowerShell
$env:PORT = "8080"; node app.js

// Windows cmd.exe
set PORT=8080
node app.js

托管平台(Heroku、Render、Vercel、Docker、Kubernetes)都有一个设置页面或配置文件来做同样的事;你的代码读取它们的方式完全一样。

一切都是字符串

大多数 process.env 的 bug 都出在这里。'false' 和 '0' 是非空字符串,所以它们是真值:

一个设置为 false 的变量,简单的判断却打印了 debug is ON,所以要和你期望的确切字符串做比较。对于数字,Number(process.env.X) 会把缺失的值变成 NaN,所以要先应用默认值再转换,就像第一个例子用 ?? 那样。

NODE_ENV

NODE_ENV 是一种约定,不是 Node.js 的功能:Node.js 从不设置它,读取它的是各种库。比如 Express 在它为 production 时会在错误页面中隐藏堆栈跟踪,很多工具也会跳过仅用于开发环境的检查。

它打印了 mode: production 和 verbose logs: false;把 'production' 改成 'development',第二行就会反过来。坚持使用 production、development 和 test,因为库检查的正是这几个词。

.env 文件:--env-file 和 dotenv

每次都在 node 前面输入所有变量很快就会让人厌烦。.env 文件把它们放在项目文件夹里,每行一个:

// .env
PORT=8080
DATABASE_URL=postgres://localhost/shop
API_KEY=dev-key-123

Node.js 20.6 及更高版本用一个参数就能读取它,不需要安装包:

node --env-file=.env app.js

在更旧的版本上,或者你更喜欢这种方式,可以安装 dotenv 包(npm install dotenv),并在入口文件的最顶部加载它,要在任何读取 process.env 的代码之前:

require('dotenv').config(); // copies .env into process.env

console.log(process.env.PORT); // 8080

两种方式都不会覆盖 shell 中已经设置的变量,所以生产环境的设置优先于文件。

缺少变量时尽早失败

缺少数据库 URL 时,程序应该在启动时就带着清楚的提示停下来,而不是一小时后在第一个请求上崩溃:

它打印了 Missing environment variables: API_KEY;在顶部加上 process.env.API_KEY = 'test';,它就会打印 Config OK。在真实的程序中,提示之后要接着调用 process.exit(1),因为部署脚本或容器平台正是通过非零退出码知道启动失败了。

永远不要提交密钥

创建 .env 的当天就把它加进 .gitignore。改为提交一个 .env.example,里面写上变量名和假的值,让其他人知道需要设置什么。一个曾经被推送到仓库的密钥应当视为已经泄露并更换,即使你后来删掉了那个提交。

常见问题

为什么 process.env.MY_VAR 是 undefined?

启动 Node.js 的那个 shell 里没有设置这个变量,或者你是在另一个终端里设置的。.env 文件也不会被自动读取:用 --env-file=.env 启动 Node.js,或者在读取值之前用 dotenv 加载它。

程序运行时可以修改 process.env 吗?

可以。赋值 process.env.X = 'value' 会修改当前进程的值,也会影响它之后启动的子进程,但永远不会影响启动 Node.js 的那个 shell。Node.js 会把你赋的值转换成字符串。

环境变量名区分大小写吗?

在 Linux 和 macOS 上区分:PORT 和 port 是两个变量。在 Windows 上不区分。坚持使用大写字母加下划线的名字,这个问题就不会出现。

浏览器能读取 process.env 吗?

不能。浏览器没有环境变量。Vite 和 Next.js 这类构建工具会在构建时把选定的变量复制到你的前端代码里,这也意味着这些值是公开的。

Coddy 编程语言插图

和 Coddy 一起学编程

开始