Next.js构建时为何需运行时环境变量?构建报错求助
问题与解决方案:Next.js + T3 Stack 运行时环境变量配置问题
问题背景
使用T3 Stack为Next.js应用配置服务端专属环境变量MONGODB_URI,目的是仅在运行时提供密钥以保护敏感信息。本地运行正常,但CI构建时出现以下问题:
- 构建阶段因
MONGODB_URI未定义触发Zod校验报错 - 添加虚拟
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
相关产品推荐
相关产品推荐

