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

Next.js容器部署时服务端非NEXT_PUBLIC_环境变量未定义问题

Next.js Docker部署后非NEXT_PUBLIC_前缀的环境变量服务端读取为undefined

本地通过yarn dev运行Next.js应用时,使用.env.local存储机密变量一切正常,但通过GitHub Actions部署到Docker容器后,仅NEXT_PUBLIC_开头的环境变量可正常读取,其余服务端变量在容器日志中显示为undefined,客户端环境变量无异常。


GitHub Actions配置

jobs:
  build_and_push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repo
        uses: actions/checkout@v2

      - name: Make envfile
        uses: SpicyPizza/create-envfile@v1.3
        with:
          envkey_NEXT_PUBLIC_JWT_EXPIRATION: ${{ vars.NEXT_PUBLIC_JWT_EXPIRATION }}
          envkey_NEXT_PUBLIC_JWT_REFRESH_TOKEN_SECRET: ${{ vars.NEXT_PUBLIC_JWT_REFRESH_TOKEN_SECRET }}
          envkey_NEXT_PUBLIC_JWT_SECRET: ${{ vars.NEXT_PUBLIC_JWT_SECRET }}
          envkey_NEXT_PUBLIC_API_BASE_URL: ${{ vars.DEV_API_BASE_URL }}
          envkey_MONGO_DB_URI: ${{ secrets.DEV_MONGO_DB_URI }}
          envkey_WEATHER_DB: ${{ vars.DEV_WEATHER_DB }}
          envkey_WILLI_WEATHER_API_KEY: ${{ secrets.WILLI_WEATHER_API_KEY }}
          file_name: .env
          fail_on_empty: false

      - name: Build container image
        run: docker build -t $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7) .

      - name: Install doctl
        uses: digitalocean/action-doctl@v2
        with:
          token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

      - name: Log in to DigitalOcean Container Registry with short-lived credentials
        run: doctl registry login --expiry-seconds 600

      - name: Remove all old images
        run: if [ ! -z "$(doctl registry repository list | grep "$(echo $IMAGE_NAME)")" ]; then doctl registry repository delete-manifest $(echo $IMAGE_NAME) $(doctl registry repository list-tags $(echo $IMAGE_NAME) | grep -o "sha.*") --force; else echo "No repository"; fi

      - name: Push image to DigitalOcean Container Registry
        run: docker push --max-concurrent-uploads 1 $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7)

      - name: Run registry garbage collection
        run: doctl registry garbage-collection start --include-untagged-manifests --force

Dockerfile配置

FROM node:16-alpine as dependencies
WORKDIR /my-project
COPY package.json yarn.lock ./
    
RUN yarn install --frozen-lockfile

FROM node:16-alpine as builder
WORKDIR /my-project
COPY . .
COPY --from=dependencies /my-project/node_modules ./node_modules
COPY ./.env ./node_modules/.env
RUN yarn build

FROM node:16-alpine as runner
WORKDIR /my-project
ENV NODE_ENV production

# If you are using a custom next.config.js file, uncomment this line.
# COPY --from=builder /my-project/next.config.js ./
COPY --from=builder /my-project/public ./public
COPY --from=builder /my-project/.next ./.next
COPY --from=builder /my-project/node_modules ./node_modules
COPY --from=builder /my-project/package.json ./package.json
COPY --from=builder /my-project/_fonts /usr/local/share/fonts
COPY --from=builder /my-project/_assets ./_assets

#install fontconfig and clear cache
RUN apk add --update fontconfig 
RUN fc-cache -f -v

EXPOSE 3000
CMD ["yarn", "start"]

容器服务端日志

### Response start here:                                                                                                                                                                    
Timestamp:  5/21/23, 9:39 AM                                                                                                                                                                
NEXT_PUBLIC_API_BASE_URL http://10.0.4.6:3000/                                                                                                                                              
MONGO_DB_URI undefined                                                                                                                                                                      
WEATHER_DB undefined                                                                                                                                                                        
WILLI_WEATHER_API_KEY undefined                                                                                                                                                            
NEXT_PUBLIC_JWT_EXPIRATION 5m                                                                                                                                                              
NEXT_PUBLIC_JWT_REFRESH_TOKEN_SECRET 7c4c1c50-3230-45bf-9eae-c9b2e401c767                                                                                                                  
NEXT_PUBLIC_JWT_SECRET dd5f3089-40c3-403d-af14-d0c228b05cb4                                                                                                                                 
Delta time =  142392    

Docker镜像中.env文件内容

/my-project/node_modules # cat .env                                                                                                                                                        
MONGO_DB_URI=mongodb+srv://mame:reJHeDc@maev.v8ilhrq.mongodb.net/?retryWrites=true&w=majority                                                                 
NEXT_PUBLIC_API_BASE_URL=http://10.0.4.6:3000/                                                                                                                                              
NEXT_PUBLIC_JWT_EXPIRATION=5m                                                                                                                                                              
NEXT_PUBLIC_JWT_REFRESH_TOKEN_SECRET=7c4c1c50-3230-45bf-9eae-c9b2e401c767                                                                                                                  
NEXT_PUBLIC_JWT_SECRET=dd5f3089-40c3-403d-af14-d0c228b05cb4                                                                                                                                 
WEATHER_DB=Weather                                                                                                                                                                          
WILLI_WEATHER_API_KEY=YjQ3MDkwMGDkN2VjQ3MDkwMGZjjOD

问题原因与解决方案

问题根源

  1. Next.js默认只会从项目根目录加载.env、.env.production等环境变量文件,不会读取node_modules目录下的.env文件。
  2. 当前Dockerfile中,仅在builder阶段将.env复制到node_modules,且runner阶段未将根目录的.env文件同步到生产环境容器中,导致服务端启动时无法读取非NEXT_PUBLIC_前缀的变量。

修正步骤

  1. 调整Dockerfile的.env文件路径
    • 在builder阶段,删除将.env复制到node_modules的命令,保留根目录的.env文件:
      FROM node:16-alpine as builder
      WORKDIR /my-project
      COPY . .
      COPY --from=dependencies /my-project/node_modules ./node_modules
      # 移除 COPY ./.env ./node_modules/.env
      RUN yarn build
      
    • 在runner阶段,新增复制根目录.env文件的命令:
      FROM node:16-alpine as runner
      WORKDIR /my-project
      ENV NODE_ENV production
      
      # 新增:将根目录的.env复制到生产环境容器
      COPY --from=builder /my-project/.env ./
      # 其余复制命令保持不变
      COPY --from=builder /my-project/public ./public
      COPY --from=builder /my-project/.next ./.next
      COPY --from=builder /my-project/node_modules ./node_modules
      COPY --from=builder /my-project/package.json ./package.json
      COPY --from=builder /my-project/_fonts /usr/local/share/fonts
      COPY --from=builder /my-project/_assets ./_assets
      
  2. 验证效果
    Next.js在生产环境启动(yarn start)时会自动加载项目根目录的.env文件,此时服务端即可正常读取非NEXT_PUBLIC_前缀的变量。

注意:非NEXT_PUBLIC_前缀的变量不会被注入到客户端代码中,这是Next.js保护敏感变量的正常行为,无需调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 05:37:29