You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Docker中Next.js构建后设置NEXT_PUBLIC_*环境变量?

Next.js「一次构建,多处部署」客户端环境变量解决方案

问题根源

你遇到的核心问题是:Next.js的NEXT_PUBLIC_*环境变量默认在构建阶段嵌入到客户端静态代码中,构建完成后这些变量就固化了。你当前的构建流程未在构建时传入这类变量,部署时通过docker-compose传递的环境变量仅能被服务器端代码读取,无法修改已打包好的客户端静态文件,因此客户端组件拿不到正确值。

可行解决方案

方案1:通过服务器端API提供客户端配置(推荐)

这个方案完全支持一次构建多处部署,核心思路是让客户端在运行时从服务器端获取配置,而非依赖构建时注入。

步骤:
  1. 创建API路由(以App Router为例)
    在app/api/config/route.ts中添加以下代码:
export async function GET() {
  return Response.json({
    backendUrl: process.env.NEXT_PUBLIC_BACKEND,
    // 其他需要给客户端的配置都可在此添加
  });
}
  1. 客户端组件获取配置
    在客户端组件中,初始化时请求该API拿到配置:
'use client';

import { useEffect, useState } from 'react';

interface ClientConfig {
  backendUrl: string;
}

export default function ClientComponent() {
  const [config, setConfig] = useState<ClientConfig | null>(null);

  useEffect(() => {
    const fetchConfig = async () => {
      const res = await fetch('/api/config');
      const data = await res.json();
      setConfig(data);
    };
    fetchConfig();
  }, []);

  if (!config) return <div>加载中...</div>;

  return <div>后端地址:{config.backendUrl}</div>;
}
  1. 保持现有Docker配置不变
    你当前通过docker-compose传递环境变量的方式无需修改,服务器端API会自动读取运行时的环境变量并返回给客户端。

方案2:运行时替换客户端代码中的占位符

若不想通过API获取配置,可在构建时用占位符替代NEXT_PUBLIC_*变量,再在容器启动前用脚本替换成运行时的环境变量。

步骤:
  1. 修改代码中的变量引用
    将客户端代码里的process.env.NEXT_PUBLIC_BACKEND替换为占位符,比如{{NEXT_PUBLIC_BACKEND}}。

  2. 修改Dockerfile添加替换脚本
    在runner阶段添加启动脚本,用sed命令替换静态文件中的占位符:

FROM node:18-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN rm -f .env*
RUN npm run build

FROM node:18-alpine AS runner

WORKDIR /app

COPY --from=builder /app/package.json ./
COPY --from=builder /app/.next .next
COPY --from=builder /app/node_modules node_modules
COPY --from=builder /app/public public

ENV NODE_ENV=production

EXPOSE 3000

# 启动前替换占位符
CMD ["/bin/sh", "-c", "sed -i 's|{{NEXT_PUBLIC_BACKEND}}|'"$NEXT_PUBLIC_BACKEND"'|g' .next/static/**/*.js && npm run start"]

注意:若静态文件路径不同或有多个占位符,需调整sed命令的匹配规则,确保覆盖所有包含占位符的文件。

方案3:服务器端组件传递配置

若客户端组件是服务器端组件的子组件,可直接在服务器端组件中读取环境变量,再通过props传递给客户端组件:

// 服务器端组件(app/page.tsx)
export default function ServerPage() {
  const backendUrl = process.env.NEXT_PUBLIC_BACKEND;
  return <ClientComponent backendUrl={backendUrl} />;
}

// 客户端组件
'use client';

export default function ClientComponent({ backendUrl }: { backendUrl: string }) {
  return <div>后端地址:{backendUrl}</div>;
}

这个方案适合不需要全局配置的场景,简单直接,但多个客户端组件需要配置时会存在代码重复。

总结

优先推荐方案1,它符合Next.js设计理念且扩展性强,后续添加新客户端配置仅需修改API路由,无需调整构建或启动流程。

内容的提问来源于stack exchange,提问作者Fabio Piunti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 03:06:04