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

Next.js构建时为何需运行时环境变量?构建报错求助

问题与解决方案:Next.js + T3 Stack 运行时环境变量配置问题

问题背景

使用T3 Stack为Next.js应用配置服务端专属环境变量MONGODB_URI,目的是仅在运行时提供密钥以保护敏感信息。本地运行正常,但CI构建时出现以下问题:

  1. 构建阶段因MONGODB_URI未定义触发Zod校验报错
  2. 添加虚拟MONGODB_URI后,构建时Mongo尝试连接失败,提示API路由被预渲染

核心问题解答

1. 服务端动态元素为何在构建时被预渲染?

Next.js默认会对所有路由(包括API路由)尝试静态优化,在构建阶段预渲染生成静态内容。如果没有明确标记路由为动态类型,哪怕是服务端专属的API,Next.js也会在构建时执行其代码,尝试预渲染结果。

2. Mongo为何在构建时尝试建立连接?

你的lib/mongodb.ts在模块加载阶段就直接创建了MongoClient并调用connect(),当API路由被预渲染时,这个模块会被加载执行,进而触发Mongo连接逻辑。构建时使用的虚拟URI无效,导致DNS解析失败。

3. 运行时密钥为何需要在构建时提供?

T3的createEnv默认在构建阶段就会校验所有环境变量(包括服务端专属变量),以此保证类型安全。默认配置下,构建过程必须能获取到MONGODB_URI才能通过校验,哪怕是虚拟值。

4. 是否必须在CI环境暴露真实密钥?

不需要。通过调整配置,可以让环境变量校验和Mongo连接逻辑只在运行时执行,避免构建阶段触发,从而无需在CI中暴露真实密钥。

具体解决方案

步骤1:调整T3环境变量校验逻辑,跳过构建阶段的服务端变量校验

修改env/server.js,添加构建时跳过校验的开关:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    NODE_ENV: z.enum(["development", "test", "production"]),
    MONGODB_URI: z.string().url(),
  },
  runtimeEnv: process.env,
  // 构建时跳过服务端变量校验,仅在运行时校验
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
});

在CI构建命令中设置SKIP_ENV_VALIDATION=true,比如:

SKIP_ENV_VALIDATION=true next build

步骤2:延迟MongoClient初始化,避免模块级执行

修改lib/mongodb.ts,将连接逻辑封装为函数,仅在请求处理时执行:

import { MongoClient } from "mongodb";
import { env } from "@/env/server.mjs";

let clientPromise: Promise<MongoClient> | null = null;

export const getClientPromise = async () => {
  if (!clientPromise) {
    const uri = env.MONGODB_URI;
    if (!uri) {
      throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
    }
    const client = new MongoClient(uri);
    clientPromise = client.connect();
  }
  return clientPromise;
};

步骤3:标记API路由为动态路由,禁止预渲染

在api/data/route.ts顶部添加动态路由标记,让Next.js仅在运行时处理该路由:

// 强制该路由为动态,构建时不预渲染
export const dynamic = 'force-dynamic';

import { getClientPromise } from "@/lib/mongodb";

export async function GET() {
  const client = await getClientPromise();
  const db = client.db();

  const data = await db
    .collection("data")
    .find({})
    .toArray();

  return Response.json({
    type: "FeatureCollection",
    features: data,
  });
}

效果验证

调整后:

  • CI构建时跳过服务端环境变量校验,无需提供真实MONGODB_URI
  • Mongo连接逻辑仅在运行时请求处理阶段执行,不会在构建时触发
  • API路由不会被预渲染,完全在服务端运行时处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:25:19