今天聊一个让不少开发者头疼的话题:在 VSCode 里给 Node.js 项目配置环境变量文件 .env。
先说说核心判断:VSCode 本身不会主动去读取、解析或注入任何 .env 文件——这个事实很重要,因为所有“变量没生效”的问题,本质上都出在运行时加载环节,而不是编辑器配置。

launch.json 的 envFile 字段只对调试生效
这是最常用也最省事的做法——不用动代码,但得明白它的适用范围:仅限于 VSCode 调试器启动的 Node.js 进程。
操作上要注意几点:
.env文件放项目根目录,跟package.json同级,编码必须是 UTF-8 无 BOM。怎么看?右下角状态栏就能查,不对的话点 “Sa ve with Encoding” 改成 “UTF-8”。- 在
.vscode/launch.json的配置里加上envFile字段,路径必须用${workspaceFolder}表达式,比如这样:"envFile": "${workspaceFolder}/.env"。千万别写成./.env或.env,某些版本里相对路径不太靠谱,而且也别指望它自动合并.env.local或者处理什么覆盖逻辑。 - 修改完
.env文件后,记得重启调试会话——VSCode 不会热重载这个文件。
终端里运行 node 命令时 .env 不生效?别怪 VSCode
VSCode 内置终端是独立的 shell 进程,跟编辑器是解耦的,不会自动去 source 或解析 .env 文件。所以如果你在终端里直接敲 node index.js,指望 .env 里的变量自动生效,那就不太现实。
几个实用建议:
- Windows 下的 cmd 或 PowerShell 不支持
NODE_ENV=development node index.js这种写法——要么报错,要么静默忽略。 - 正确的做法:安装
cross-env,命令是npm install --sa ve-dev cross-env。然后在package.json的 scripts 里写"dev": "cross-env NODE_ENV=development node index.js"。 - 如果要用 launch.json 启动带环境变量的终端命令,把
runtimeExecutable设成"cross-env",runtimeArgs写成["NODE_ENV=development", "node", "index.js"]。注意:别把环境变量塞进args字段里,那是传给 Node.js 的参数,不是 shell 环境变量。
require('dotenv').config() 必须在入口文件最顶部
这是最可靠的方式——在代码层面加载环境变量,但顺序和路径非常容易出错。
- 如果你用 ESM(ES Module),推荐写法是
import 'dotenv/config';,而且要放在所有其他import之前,包括import { createServer } from 'http'这种系统模块。 - CommonJS 下同理:
require('dotenv').config();必须在const app = express();或者数据库连接之前执行——差一行都可能出问题。 - 路径错误是最常见的坑:
require('dotenv').config({ path: './config/.env' })里的路径是相对于当前 JS 文件的,不是项目根目录。比如入口是src/index.js,.env在根目录,那就要写成{ path: '../.env' }。 - 还有一个隐藏问题:文件如果包含 BOM 或者不可见的 Unicode 字符(比如零宽空格),
dotenv会静默失败,process.env全为空。用 VSCode 打开.env,切换到纯文本模式检查一下有没有异常字符。
DotENV 插件只负责高亮,跟运行无关
很多人装了插件后看到 .env 文件有颜色,就以为变量能用了——其实不然。插件只做两件事:语法高亮和颜色标记。
- 检查右下角语言模式是不是
Environment,如果不是,点一下切换过来,否则插件不触发高亮。 - 如果你用自定义文件名比如
.env.staging,得手动在settings.json里配置:"files.associations": { "*.staging": "environment" }。 - 记住一条:插件完全不参与运行时加载。
process.env.API_URL还是 undefined 的话,这很正常——插件只是帮你少写错一个等号而已。
最后说一个容易被忽略的点:envFile 和 require('dotenv').config() 是两条独立路径,可以同时用,也可以只用一条。但如果同时用了,要注意变量优先级——envFile 加载的变量会覆盖 dotenv 解析的同名变量,而系统环境变量又会覆盖这两者。调试时看到的值,未必是你代码里真正拿到的值。这点很关键,值得多想一下。