- 文档
- 教程
- 知识库
【免费下载链接】til
:memo: Today I Learned
导读
在 Next.js 应用中,.env.development、.env.production等环境变量文件为不同环境(开发、测试、生产)提供了无缝切换配置的能力,但默认情况下这些变量不会进入浏览器端的客户端代码。本文基于 til 仓库的实战笔记,讲解为什么process.env.API_BASE_URL在客户端组件中会得到undefined,以及如何通过NEXT_PUBLIC_前缀把非敏感变量(如 API 基础地址)公开暴露给前端;同时结合仓库中的相关笔记,补充.env*文件的加载顺序、变量优先级与真实迁移场景,让你彻底掌握 Next.js 环境变量的公开化机制。
从.env文件说起:按环境切分配置
在 Next.js 项目中,环境变量的常见做法是把它写在 dotenv 格式的文件里,并按运行环境拆分。你可以在.env.development和.env.production中分别定义变量,从而让同一份代码在不同环境下读取到不同的值。
一个典型场景就是 API 请求的基础地址(base URL):开发环境指向本地服务器,生产环境指向线上服务器。可以这样定义:
API_BASE_URL=localhost:3000/api/v1例如在.env.development中写入上述内容,开发环境的服务就能读到它;同理,在.env.production中写入线上地址,生产构建就使用线上地址。这是 dotenv 文件作为“环境级配置载体”的核心价值。
注意:上例中的
localhost:3000/api/v1只是笔记中的示意写法,实际使用时应包含协议,例如http://localhost:3000/api/v1或https://api.example.com/api/v1,否则请求方无法正确解析。
客户端代码读不到环境变量:默认被排除在构建之外
把变量写进.env.development/.env.production后,问题很快就会出现:从任何客户端页面或组件里都取不到这个值。
process.env.API_BASE_URL //=> undefined这是 Next.js 有意为之的安全设计。环境变量里存放的往往是私钥(private keys)、密钥(secrets)等敏感信息,如果默认就把所有环境变量打进公开的客户端代码(client code)包,等于把密钥直接暴露给任何能查看页面源码的人。因此:
- 服务端(Server Components、API Routes、
getServerSideProps等)可以读取全部环境变量; - 客户端(浏览器端执行的组件与页面代码)默认读不到任何环境变量;
- Next.js在构建时默认将所有环境变量排除出客户端 bundle。
换句话说,不是变量没定义,而是 Next.js 出于安全考虑,刻意不让它进入浏览器可见的作用域。
用 NEXT_PUBLIC_ 前缀公开变量
如果某个变量的值并非机密(比如 API 基础地址),你希望它出现在浏览器端代码里,办法就是给变量名加上NEXT_PUBLIC_前缀:
NEXT_PUBLIC_API_BASE_URL=localhost:3000/api/v1加上前缀之后,这个变量在任何客户端和服务端代码中都可以访问:
process.env.NEXT_PUBLIC_API_BASE_URL //=> 'localhost:3000/api/v1'这背后的机制是:Next.js 在构建时会对代码中出现的process.env.NEXT_PUBLIC_*进行静态替换(inline)——它不是在运行时去读系统环境,而是在编译阶段就把字面量直接写入产出的 JavaScript 文件里。这也带来两个重要推论:
- 公开变量在构建时固化:
NEXT_PUBLIC_变量的值取自构建(build)那一刻的环境,而不是运行时环境。如果你改了.env.production中的值,需要重新构建部署才能让线上生效。 - 只适用于非敏感信息:任何加了
NEXT_PUBLIC_的变量都会以明文形式出现在浏览器可下载的 bundle 中,绝对不要用它存放 API 密钥、数据库密码、签名密钥等机密。
命名约定一览
| 变量类别 | 示例 | 客户端可读 | 用途 |
|---|---|---|---|
| 普通环境变量 | API_BASE_URL | 否(返回undefined) | 服务端密钥、内部配置 |
| 公开环境变量 | NEXT_PUBLIC_API_BASE_URL | 是 | 需要进入浏览器 bundle 的非敏感值 |
结合仓库笔记:.env 文件如何被加载与覆盖
要让NEXT_PUBLIC_变量真正“按环境生效”,还需要理解 Next.js 加载.env*文件的顺序。仓库中的另一篇笔记 precedence-of-dot-env-files.md 给出了完整的规则:
一个活跃开发中的项目里,.env*文件往往会有很多变体:
$ ls -a -1 .env* .env .env.development .env.development.local .env.development.local.example .env.local .env.production .env.testNext.js 的加载逻辑是:
- 始终尝试加载
.env与.env.local(test环境除外,测试中不加载.env.local); - 根据
NODE_ENV(取值development、test、production)再加载对应的环境专用文件,例如开发环境会加载.env.development与.env.development.local; - 像
.env.development.local.example这类文件并不在加载清单里,它只是 dotenv 模板文件的社区约定命名(提供一份可复制的示例模板)。
变量覆盖优先级从高到低为:系统环境(即已经存在于process.env中的变量)最高,其次是按下列顺序查找文件,找到即用、不再继续:
.env.$(NODE_ENV).local.env.local.env.$(NODE_ENV).env
把这些规则与本文主题结合,可以得出一个实战要点:如果你希望开发环境使用http://localhost:3000/api/v1、生产环境使用线上地址,可以在.env.development和.env.production中分别定义NEXT_PUBLIC_API_BASE_URL;而.env.local中定义的公开变量会覆盖同名变量,适合本地临时调试。
仓库中的真实场景:全局批量迁移 NEXT_PUBLIC_ 变量
仓库里还有一篇与NEXT_PUBLIC_直接相关的实战笔记 negative-look-ahead-search-with-ripgrep.md,记录了一次真实的重构过程:在一个大型 monorepo 中,需要把大量NEXT_PUBLIC_SANITY_DATASET变量统一改名为NEXT_PUBLIC_SANITY_DATASET_ID(注意末尾追加了_ID)。
如果直接搜索NEXT_PUBLIC_SANITY_DATASET,会返回一大堆已经改过名的结果,难以定位“还剩下哪些旧变量”。笔记给出的方案是使用正则的负向前瞻(negative look-ahead),匹配“后面不跟_ID”的旧变量:
$ rg --pcre2 'NEXT_PUBLIC_SANITY_DATASET(?!_ID)' --hidden --glob '!node_modules/**' --glob '!.git/**'关键点在于:默认的 ripgrep 正则引擎(Rust 正则库)不支持 look-around,直接执行会报regex parse error,错误信息会明确提示需要使用--pcre2标志;加上--pcre2后,就可以精确列出所有仍在使用旧变量名的文件与行号,例如.env.development中的NEXT_PUBLIC_SANITY_DATASET=production。
这个场景恰好展示了NEXT_PUBLIC_变量常见的生命周期:它们广泛散落在.env*配置文件、服务端脚本和前端代码中,重命名或迁移时需要精确的检索手段。
实战检查清单
综合本文内容,使用NEXT_PUBLIC_变量时建议遵循以下清单:
- 确认值非敏感:要公开的变量绝不能在浏览器 bundle 中泄露机密信息;
- 统一前缀命名:客户端需要读取的变量一律以
NEXT_PUBLIC_开头,例如NEXT_PUBLIC_API_BASE_URL; - 按环境拆分文件:在
.env.development/.env.production(或带.local的优先级更高变体)中定义不同取值; - 记住构建时替换:修改
NEXT_PUBLIC_变量后必须重新构建(next build)并重新部署,浏览器端才会拿到新值; - 服务端变量不加前缀:仅供服务端使用的密钥保持普通命名,避免误入客户端 bundle;
- 迁移时精确检索:批量重命名
NEXT_PUBLIC_变量时,可用rg --pcre2配合负向前瞻只命中旧变量。
小结
Next.js 出于安全考虑默认不把环境变量打进客户端代码,process.env.API_BASE_URL在浏览器端返回undefined是预期行为而非 bug。要让非敏感变量公开可见,只需给变量名加上NEXT_PUBLIC_前缀,它就会被构建器静态内联进客户端 bundle,从而在页面、组件与服务端代码中统一通过process.env.NEXT_PUBLIC_*读取。结合 til 仓库中关于.env*加载顺序与 ripgrep 迁移的笔记,你可以在真实项目中正确组织、覆盖并维护这些公开环境变量。
- 文档
- 教程
- 知识库
【免费下载链接】til
:memo: Today I Learned
相关推荐
给 Vane 接上外部 SearXNG:2 处配置跑通搜索
给 Vane 接上外部 SearXNG:2 处配置跑通搜索 Vane 是一个 AI 问答引擎,它的联网检索能力全部依赖外部 SearXNG 实例。接入 Sear
人工智能大模型AI 应用本地部署后端前端papers-notebook揭秘:5个必读的分布式调度器论文及其核心思想
papers notebook揭秘:5个必读的分布式调度器论文及其核心思想 在分布式系统领域,高效的资源调度是提升集群性能的关键。 papers noteboo
CMake `<PackageName>_ROOT` 环境变量详解:用环境变量为 `find_package` 指定搜索前缀
CMake <PackageName _ROOT 环境变量详解:用环境变量为 find_package 指定搜索前缀 <PackageName _ROOT 是
构建工具开发工具CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考