• zxb的博客
    • 运维
      • 🧊即插即更:移动硬盘与 U 盘的自动同步方案
      • ⛳FRP穿透个人博客——SSL安全篇
      • 📄Github Action自动化部署Vue3项目
      • 🎲Docker Desktop 代理配置:让镜像拉取更稳更快
      • 🤓FRP穿透搭建个人博客(白嫖SSL版)
      • 🪁FRP穿透搭建个人博客
      • 📄Kubeeasy安装K8s集群(附独家报错解决)
      • 📄不用 Kubernetes,Docker Compose 也能实现零停机蓝绿发布
    • 技术体验
      • 🛡️别再找插件了,美团出品的Tabbit才是真正的AI浏览器
      • 💧GitHub 霸榜!Tabbit平替:给浏览器装上“最强大脑”,这才是真·AI 浏览器插件
    • 自制软件插件
      • 🧋🧧 仪式感拉满!这款开源“年味”小游戏,带你瞬间找回童年快乐!
      • 🕸️摸鱼神器——摸了吗
      • 🔍🚀 思源笔记 S3 插件 v1.0.2 更新:手把手教你配置 PicList 导出
      • 🌊🚀 思源笔记 S3 插件 v1.0.3 更新:一键解锁 BM.md 精美排版!
      • 🥔AE机器人大模型案例
      • Claude Code 终于会"叫"了 —— 一个 10MB 小工具,让 AI 跑完任务发个声
    • 开发小技巧
      • 🪴【保姆级】NAS 骚操作:白嫖百 T 网盘做图床!阿里云/百度秒变“私有云相册”,快到飞起!
    • 后端技术
      • 🚁解决 Spring Session 分布式部署难题:Redis 集成指南
      • 📄使用ThreadLocal实现用户身份认证
      • SpringAI
        • 别再手写 HTTP 客户端调 AI 了!Spring AI 官方出手,一行代码搞定多模型切换
      • 📄使用注解+反射实现自动填充
      • Spring
        • 🔁循环依赖:一个Spring经典坑
        • Spring如何解决依赖循环
        • 🫛什么是Spring Bean
      • Java基础
        • 什么是序列化和反序列化?
        • 📄Java中HashMap的原理
      • 📄分布式系统中的"保险箱":事务Outbox模式深度解析
    • 📑前端技术
      • 🫚axios工具类
      • 🍛Vite项目屏幕适配的两种方案,超详细
      • 📕vue-router小技巧:通过route传参动态设置页面
      • 📄Next.js 中 NEXT_PUBLIC_ 环境变量为何修改后不生效
    • 疑难杂症
      • 🕙SpringWeb报错——CORS问题解决
      • 📄一行 JVM 参数解决 HttpClient 卡死:强制 Java 禁用 IPv6
      • 📄修复github action注入npm包权限问题
zxb的博客前端技术

Next.js 中 NEXT_PUBLIC_ 环境变量为何修改后不生效

访问次数 2559 次创建时间 2026-03-27 11:08

Next.js 中 NEXT_PUBLIC_ 环境变量为何修改后不生效

在 Next.js 项目中,一个常见现象是:容器里的环境变量已经更新,执行 echo​ 也能看到新值,但浏览器端仍然请求旧地址。问题通常不在环境变量是否成功注入,而在于对 NEXT_PUBLIC_ 变量生效时机的理解。

核心原因:NEXT_PUBLIC_ 是构建时变量

Next.js 会把所有以 NEXT_PUBLIC_​ 开头的环境变量暴露给浏览器端代码。在执行 npm run build​(即 next build​)时,这些变量的值会被内联替换并写入最终生成的 JavaScript 静态文件。

例如:

NEXT_PUBLIC_API_URL=https://api-old.example.com npm run build

客户端代码:

const apiUrl = process.env.NEXT_PUBLIC_API_URL;

在构建产物中,其效果近似于:

const apiUrl = "https://api-old.example.com";

因此,它不是浏览器运行时动态读取的配置,而是构建阶段已经确定的常量。

为什么容器启动时修改变量没有效果

假设镜像构建时使用了旧地址,等到容器启动时才注入新值:

docker run \
  -e NEXT_PUBLIC_API_URL=https://api-new.example.com \
  your-next-app

此时容器进程确实能读到新值:

echo "$NEXT_PUBLIC_API_URL"

但前端 JavaScript 文件早已在镜像构建阶段生成,其中仍然写着旧地址。浏览器下载的是这些静态文件,自然不会读取容器启动后才设置的变量。

简而言之:

容器中的环境变量是新值,不代表已经构建完成的浏览器端代码也是新值。

本地开发时的缓存影响

使用 npm run dev​ 时,Next.js 也可能因为 .next​ 缓存或开发服务未重启而继续使用旧配置。修改 .env​、.env.local 等文件后,建议:

  1. 停止开发服务;
  2. 删除 .next 缓存目录;
  3. 重新执行 npm run dev。
rm -rf .next
npm run dev

如果使用 Windows PowerShell:

Remove-Item -Recurse -Force .next
npm run dev

可选解决方案

方案一:在构建阶段传入正确变量

如果每个环境都单独构建镜像,可以在构建时注入变量:

ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL

RUN npm run build

构建镜像时传值:

docker build \
  --build-arg NEXT_PUBLIC_API_URL=https://api.example.com \
  -t your-next-app .

该方式简单直接,但不同环境需要不同构建产物。

方案二:通过服务端读取运行时变量

不要在客户端直接读取 NEXT_PUBLIC_ 变量,而是在服务端代码中读取普通环境变量,再通过接口、服务端组件或页面数据传给客户端。

const apiUrl = process.env.API_URL;

普通服务端环境变量可在 Node.js 进程运行时读取,更适合容器启动阶段注入。

需要注意:不要把密码、密钥等敏感值发送给客户端。

方案三:提供运行时配置文件

容器启动时生成一个浏览器可访问的配置文件,例如 /runtime-config.js:

window.__RUNTIME_CONFIG__ = {
  API_URL: "https://api.example.com"
};

业务代码在浏览器端读取:

const apiUrl = window.__RUNTIME_CONFIG__.API_URL;

这种方式可以实现“构建一次、部署到多个环境”,但需要处理类型声明、加载顺序、缓存策略以及配置文件生成流程。

方案四:使用相对路径与反向代理

如果前端和 API 由同一域名提供,可以让前端始终请求相对路径:

fetch("/api/users");

再由 Nginx、Ingress 或网关把 /api 转发到实际后端。这样可以减少前端对环境地址的依赖,也通常更适合容器化部署。

排查清单

遇到变量修改后不生效时,可以依次检查:

  • 变量是否以 NEXT_PUBLIC_ 开头;
  • 变量是在 next build 之前还是之后设置的;
  • 当前运行的镜像是否使用新变量重新构建;
  • 浏览器下载的 JavaScript 文件中是否仍包含旧值;
  • .next 目录是否残留缓存;
  • 开发服务或生产进程是否已经重启;
  • 浏览器、CDN、Service Worker 是否缓存了旧静态资源;
  • 该配置是否更适合改为服务端运行时变量或反向代理配置。

总结

NEXT_PUBLIC_ 的关键语义不是“公开的运行时环境变量”,而是“在构建时写入客户端代码的公开变量”。

如果变量需要在容器启动时动态变化,应避免仅依赖 NEXT_PUBLIC_,改用服务端读取、运行时配置文件或反向代理;如果继续使用它,就必须在构建前设置正确的值并重新生成前端产物。

评论

0 条评论

暂无评论,欢迎第一个留言。

验证码
回复评论
验证码
举报内容
验证码
由 b8l8u8e8 提供支持