NextJS应用无法从docker-compose.yml读取环境变量求助
核心原因
Next.js 的NEXT_PUBLIC_*前缀环境变量默认是构建时注入的——也就是说这些变量会在yarn build阶段被打包进静态 JS 文件,运行时容器内的process.env变量无法覆盖已打包的内容。你当前的配置错把运行时变量(docker-compose的environment)当成了构建时变量,同时Dockerfile的ARG参数没有和docker-compose的配置关联,导致构建时根本没拿到目标变量。
解决方案一:构建时注入变量(静态打包)
这种方式适合变量固定、不需要运行时修改的场景,直接在构建镜像时把变量注入应用:
修改docker-compose.yml
把environment替换为build.args,传递构建时参数:services: cc_fe: build: context: ./frontend args: - NEXT_PUBLIC_LOGO=/xyz.png - NEXT_PUBLIC_LOGODARK=/logo-dark.png - NEXT_PUBLIC_BASE_URL=https://example.com/api container_name: cc_fe ports: - "4096:4096" volumes: - ./frontend/public/:/app/public更新Dockerfile
定义所有需要的构建参数,并转为环境变量供构建时使用:FROM node:16 RUN apt-get update && apt-get install -y yarn WORKDIR /app # 声明所有需要的构建参数 ARG NEXT_PUBLIC_LOGO ARG NEXT_PUBLIC_LOGODARK ARG NEXT_PUBLIC_BASE_URL # 将构建参数转为环境变量,确保构建阶段可读取 ENV NEXT_PUBLIC_LOGO=${NEXT_PUBLIC_LOGO} ENV NEXT_PUBLIC_LOGODARK=${NEXT_PUBLIC_LOGODARK} ENV NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL} # 注:如果不需要本地.env文件覆盖变量,可删除此行 # COPY ./.env . COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile COPY . . RUN yarn build CMD if [ -z "$PORT" ]; then yarn start -p $(grep '^PORT=' .env | cut -d '=' -f2); else yarn start -p "$PORT"; fi
解决方案二:运行时动态读取变量(Next.js 12+)
如果需要在容器运行时动态修改变量,可使用Next.js的Runtime Config特性:
配置next.config.js
在项目根目录添加或修改该文件,声明运行时可读取的公共变量:module.exports = { runtimeConfig: { public: { logo: process.env.NEXT_PUBLIC_LOGO, logodark: process.env.NEXT_PUBLIC_LOGODARK, baseUrl: process.env.NEXT_PUBLIC_BASE_URL, }, }, };在应用中读取变量
不要直接用process.env,改用getRuntimeConfig():import { getRuntimeConfig } from 'next/config'; const { public: publicConfig } = getRuntimeConfig(); // 使用变量 console.log(publicConfig.logo);保留原有docker-compose.yml配置
这种方式不需要修改Dockerfile的ARG/ENV配置,docker-compose的environment会在容器运行时生效,但注意:仅SSR/SSG页面能动态读取,纯静态生成的页面(使用getStaticProps)仍会使用构建时变量。
为什么之前的操作无效?
你在容器shell中看到的process.env是运行时环境变量,但Next.js默认会把NEXT_PUBLIC_*变量在yarn build阶段就硬编码进静态资源里,运行时的变量无法覆盖已打包的内容,所以应用中读不到。
内容的提问来源于stack exchange,提问作者Cagrison

