Next.js 环境变量完全指南
本文档详细说明 Next.js 中如何使用环境变量,包括文件类型、加载顺序、优先级规则和最佳实践。
📋 目录
环境变量文件类型
Next.js 支持以下环境变量文件:
基础文件
| 文件名 | 说明 | 使用场景 |
|---|---|---|
.env | 默认环境变量,所有环境都会加载 | 公共配置 |
.env.local | 本地环境变量,不应提交到 Git | 本地开发覆盖 |
.env.development | 开发环境专用 (next dev) | 开发环境配置 |
.env.production | 生产环境专用 (next build + next start) | 生产环境配置 |
.env.test | 测试环境专用 (jest 或 vitest) | 测试环境配置 |
组合文件
| 文件名 | 说明 |
|---|---|
.env.development.local | 开发环境的本地覆盖 |
.env.production.local | 生产环境的本地覆盖 |
.env.test.local | 测试环境的本地覆盖 |
加载顺序和优先级
🎯 优先级规则(数字越小,优先级越高)
开发环境 (next dev)
1. .env.development.local ← 最高优先级
2. .env.local ← ⚠️ 注意:.env.test.local 不会加载
3. .env.development
4. .env ← 最低优先级
生产环境 (next build + next start)
1. .env.production.local ← 最高优先级
2. .env.local ← ⚠️ 注意:.env.test.local 不会加载
3. .env.production
4. .env ← 最低优先级
测试环境 (jest / vitest)
1. .env.test.local ← 最高优先级
2. .env.test
3. .env ← 最低优先级
注意:.env.local 不会在测试环境加载(确保测试一致性)
📊 优先级可视化
┌─────────────────────────────────────────────┐
│ 优先级从上到下递减 │
├─────────────────────────────────────────────┤
│ .env.[environment].local (最高) │
│ ↓ 会覆盖下面的配置 │
│ .env.local │
│ ↓ 会覆盖下面的配置 │
│ .env.[environment] │
│ ↓ 会覆盖下面的配置 │
│ .env (最低) │
└─────────────────────────────────────────────┘
🔍 实际加载示例
假设有以下文件和配置:
# .env
NEXT_PUBLIC_API_URL=http://default-api.com
DATABASE_URL=default-db
# .env.development
NEXT_PUBLIC_API_URL=http://dev-api.com
# .env.local
NEXT_PUBLIC_API_URL=http://local-api.com
运行 next dev 时的结果:
process.env.NEXT_PUBLIC_API_URL = "http://local-api.com" // 来自 .env.local
process.env.DATABASE_URL = "default-db" // 来自 .env
解释:
.env.local的NEXT_PUBLIC_API_URL覆盖了其他文件DATABASE_URL只在.env中定义,所以使用该值
NODE_ENV 的特殊性
⚠️ 重要特性
- 不能在
.env文件中设置NODE_ENV - Next.js 会自动设置
NODE_ENV:next dev→NODE_ENV=developmentnext build→NODE_ENV=productionnext start→NODE_ENV=production
实验:尝试覆盖 NODE_ENV
# .env.local
NODE_ENV=production # ❌ 这不会生效!
# 命令行
$ cross-env NODE_ENV=production next dev
# Next.js 警告:
⚠ You are using a non-standard "NODE_ENV" value in your environment.
This creates inconsistencies in the project and is strongly advised against.
结果:process.env.NODE_ENV 仍然是 "development"
✅ 正确的做法
如果需要自定义环境标识,使用自定义变量:
# .env.staging
NEXT_PUBLIC_ENV=staging
NEXT_PUBLIC_API_URL=http://staging-api.com
// 代码中使用
const env = process.env.NEXT_PUBLIC_ENV || 'development';
环境变量类型
1. 服务端环境变量(默认)
# .env
DATABASE_URL=postgresql://localhost:5432/mydb
API_SECRET=my-secret-key
特点:
- ✅ 只在服务端可用
- ✅ 不会暴露到浏览器
- ✅ 可以存储敏感信息
使用:
// app/api/route.ts (服务端)
export async function GET() {
const dbUrl = process.env.DATABASE_URL; // ✅ 可以访问
return Response.json({ success: true });
}
// app/page.tsx (客户端组件)
'use client';
export default function Page() {
console.log(process.env.DATABASE_URL); // ❌ undefined(安全)
}
2. 浏览器端环境变量
使用 NEXT_PUBLIC_ 前缀:
# .env
NEXT_PUBLIC_API_URL=http://api.example.com
NEXT_PUBLIC_ANALYTICS_ID=GA-123456
特点:
- ✅ 客户端和服务端都可用
- ⚠️ 会暴露到浏览器(内联到 JavaScript bundle)
- ❌ 不要存储敏感信息
使用:
// app/page.tsx (客户端组件)
'use client';
export default function Page() {
const apiUrl = process.env.NEXT_PUBLIC_API_URL; // ✅ 可以访问
return <div>API: {apiUrl}</div>;
}
⚠️ 安全警告:
# ❌ 错误示例 - 敏感信息不要用 NEXT_PUBLIC_
NEXT_PUBLIC_DATABASE_PASSWORD=secret123 # 会暴露到浏览器!
# ✅ 正确示例 - 敏感信息不加前缀
DATABASE_PASSWORD=secret123 # 只在服务端可用
实战示例
场景 1:多环境配置
文件结构
项目根目录/
├── .env # 公共配置
├── .env.development # 开发环境
├── .env.production # 生产环境
├── .env.local # 本地覆盖(不提交)
└── .gitignore
.env(默认配置)
# 公共配置 - 所有环境共享
APP_NAME=PayUnify
APP_VERSION=1.0.0
.env.development(开发环境)
# 开发环境配置
NEXT_PUBLIC_API_URL=http://localhost:8097
NEXT_PUBLIC_ENV=development
# 开发环境数据库
DATABASE_URL=postgresql://localhost:5432/payunify_dev
.env.production(生产环境)
# 生产环境配置
NEXT_PUBLIC_API_URL=https://api.payunify.com
NEXT_PUBLIC_ENV=production
# 生产环境数据库(敏感信息,通常由服务器设置)
DATABASE_URL=postgresql://prod-db.example.com:5432/payunify
.env.local(本地开发覆盖)
# 本地开发时的个性化配置
# 此文件不提交到 Git,每个开发者可以有自己的配置
# 如果你在本地测试生产 API
NEXT_PUBLIC_API_URL=http://124.222.202.16:8089
# 本地数据库
DATABASE_URL=postgresql://localhost:5432/payunify_local
.gitignore
# 环境变量
.env*.local
.env.local
场景 2:条件配置加载
// lib/config.ts
export const config = {
apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8097',
env: process.env.NEXT_PUBLIC_ENV || 'development',
isDev: process.env.NODE_ENV === 'development',
isProd: process.env.NODE_ENV === 'production',
// 服务端专用配置
database: {
url: process.env.DATABASE_URL,
},
// 第三方服务
analytics: {
googleId: process.env.NEXT_PUBLIC_GA_ID,
},
};
场景 3:API 客户端配置
// services/apiClient.ts
class ApiClient {
private baseURL: string;
constructor() {
// 根据协议决定使用代理还是直连
const isHttps = typeof window !== 'undefined' &&
window.location.protocol === 'https:';
if (isHttps) {
// HTTPS 环境使用代理避免混合内容
this.baseURL = '/api/proxy';
} else {
// HTTP 环境直连
this.baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8097';
}
console.log('Environment:', process.env.NODE_ENV);
console.log('API Base URL:', this.baseURL);
}
}
最佳实践
1. 文件组织策略
✅ 推荐结构
.env # 提交到 Git - 默认配置
.env.example # 提交到 Git - 配置模板
.env.development # 提交到 Git - 开发环境
.env.production # 提交到 Git - 生产环境
.env.local # 不提交 - 本地覆盖
.env.example(配置模板)
# API 配置
NEXT_PUBLIC_API_URL=http://localhost:8097
# 数据库配置(示例值)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
# 第三方服务(示例值)
NEXT_PUBLIC_GA_ID=your-ga-id
STRIPE_SECRET_KEY=your-stripe-key
2. 安全实践
✅ 正确做法
# 服务端专用(敏感信息)
DATABASE_PASSWORD=secret123
API_SECRET_KEY=very-secret
STRIPE_SECRET_KEY=sk_live_xxx
# 客户端可见(非敏感信息)
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_GA_ID=GA-123456
❌ 错误做法
# ❌ 敏感信息加了 NEXT_PUBLIC_ 前缀
NEXT_PUBLIC_DATABASE_PASSWORD=secret123 # 会暴露到浏览器!
NEXT_PUBLIC_API_SECRET=xxx # 会暴露到浏览器!
3. Git 版本控制
.gitignore
# 环境变量 - 忽略本地配置
.env*.local
.env.local
# 不要忽略这些
# .env
# .env.example
# .env.development
# .env.production
4. 团队协作
新成员入职流程
# 1. 克隆项目
git clone <repo>
cd project
# 2. 复制环境配置
cp .env.example .env.local
# 3. 修改个人配置
nano .env.local
5. 部署配置
Vercel 部署
# 在 Vercel 项目设置中配置环境变量
Environment Variables:
NEXT_PUBLIC_API_URL=https://api.production.com
DATABASE_URL=postgresql://...(敏感信息)
STRIPE_SECRET_KEY=sk_live_xxx
Docker 部署
# docker-compose.yml
services:
frontend:
environment:
- NODE_ENV=production
- NEXT_PUBLIC_API_URL=http://api:8080
- DATABASE_URL=${DATABASE_URL} # 从宿主机加载
常见问题
Q1: 为什么我的环境变量没有生效?
可能原因:
-
没有重启开发服务器
# ❌ 运行中修改 .env 文件不会自动生效
# ✅ 需要重启
npm run dev -
优先级问题
# .env.local 会覆盖 .env.development
# 检查是否有优先级更高的文件 -
客户端组件访问服务端变量
// ❌ 客户端无法访问
'use client';
console.log(process.env.DATABASE_URL); // undefined
// ✅ 需要 NEXT_PUBLIC_ 前缀
console.log(process.env.NEXT_PUBLIC_API_URL); // 正常 -
构建时内联
# NEXT_PUBLIC_ 变量在构建时内联到代码中
# 修改后需要重新构建
npm run build
Q2: 如何在不同环境切换 API 地址?
方案 1:使用 .env.local(推荐)
# .env.local
NEXT_PUBLIC_API_URL=http://staging-api.com
# 切换环境时修改这个文件
# 重启: npm run dev
方案 2:使用环境特定文件
# .env.development
NEXT_PUBLIC_API_URL=http://dev-api.com
# .env.production
NEXT_PUBLIC_API_URL=http://prod-api.com
# 使用不同命令
npm run dev # 使用 .env.development
npm run build # 使用 .env.production
npm start
方案 3:使用自定义环境变量
# .env.staging
NEXT_PUBLIC_ENV=staging
NEXT_PUBLIC_API_URL=http://staging-api.com
// 代码中条件判断
const apiUrl = process.env.NEXT_PUBLIC_ENV === 'staging'
? 'http://staging-api.com'
: process.env.NEXT_PUBLIC_API_URL;
Q3: NODE_ENV 可以自定义吗?
答案:不推荐
# ❌ 不推荐 - Next.js 会警告
cross-env NODE_ENV=staging next dev
# ✅ 推荐 - 使用自定义变量
cross-env NEXT_PUBLIC_ENV=staging next dev
原因:
- Next.js 依赖
NODE_ENV进行优化 - 非标准值会导致构建行为不一致
- 使用自定义变量更灵活安全
Q4: 如何调试环境变量?
方法 1:在代码中打印
// app/page.tsx
console.log('NODE_ENV:', process.env.NODE_ENV);
console.log('API URL:', process.env.NEXT_PUBLIC_API_URL);
console.log('All NEXT_PUBLIC vars:',
Object.keys(process.env)
.filter(key => key.startsWith('NEXT_PUBLIC_'))
.reduce((obj, key) => ({ ...obj, [key]: process.env[key] }), {})
);
方法 2:创建调试页面
// app/env-test/page.tsx
export default function EnvTest() {
const envVars = Object.keys(process.env)
.filter(key => key.startsWith('NEXT_PUBLIC_'))
.reduce((obj, key) => ({ ...obj, [key]: process.env[key] }), {});
return (
<div>
<h1>环境变量调试</h1>
<p>NODE_ENV: {process.env.NODE_ENV}</p>
<pre>{JSON.stringify(envVars, null, 2)}</pre>
</div>
);
}
方法 3:检查启动日志
npm run dev
# 查看输出中的环境变量加载信息
# ▲ Next.js 15.5.5 (Turbopack)
# - Environments: .env.local, .env.development, .env
Q5: 生产环境如何管理敏感信息?
最佳实践:
-
不要在代码中硬编码
// ❌ 错误
const apiKey = 'sk_live_xxxxx';
// ✅ 正确
const apiKey = process.env.STRIPE_SECRET_KEY; -
使用平台环境变量
- Vercel: 项目设置 → Environment Variables
- Docker: docker-compose.yml 或启动参数
- 服务器: 系统环境变量
-
使用密钥管理服务
- AWS Secrets Manager
- HashiCorp Vault
- Google Secret Manager
-
分层管理
# .env.production(提交到 Git)
NEXT_PUBLIC_API_URL=https://api.production.com
# 服务器环境变量(不提交)
DATABASE_URL=postgresql://...
STRIPE_SECRET_KEY=sk_live_...
Q6: 如何处理多个子环境?
场景:开发、测试、预发布、生产
# 创建自定义环境文件
.env.dev
.env.test
.env.staging
.env.production
方案 1:使用 dotenv-cli
npm install -D dotenv-cli
# package.json
{
"scripts": {
"dev": "next dev",
"dev:test": "dotenv -e .env.test -- next dev",
"dev:staging": "dotenv -e .env.staging -- next dev"
}
}
方案 2:使用自定义脚本
// scripts/load-env.js
const fs = require('fs');
const path = require('path');
const env = process.argv[2] || 'development';
const envFile = path.resolve(process.cwd(), `.env.${env}`);
if (fs.existsSync(envFile)) {
require('dotenv').config({ path: envFile });
}
# package.json
{
"scripts": {
"dev:staging": "node scripts/load-env.js staging && next dev"
}
}
快速参考
环境变量优先级(开发环境)
.env.development.local (最高)
↓
.env.local
↓
.env.development
↓
.env (最低)
变量类型对比
| 前缀 | 客户端 | 服务端 | 用途 |
|---|---|---|---|
NEXT_PUBLIC_ | ✅ | ✅ | 公开配置 |
| 无前缀 | ❌ | ✅ | 敏感配置 |
常用命令
# 开发模式
npm run dev # 使用 .env.development
# 生产构建
npm run build # 使用 .env.production
npm start # 运行生产构建
# 自定义环境
cross-env NEXT_PUBLIC_ENV=staging npm run dev
调试检查清单
- 重启开发服务器
- 检查文件优先级(.env.local > .env.development)
- 客户端变量必须有
NEXT_PUBLIC_前缀 - 检查拼写和大小写
- 查看启动日志中的环境变量加载信息
总结
✅ 最佳实践总结
-
文件管理
- 提交
.env.example作为模板 .env.local用于本地覆盖,不提交- 使用
.env.development和.env.production区分环境
- 提交
-
安全原则
- 敏感信息不用
NEXT_PUBLIC_前缀 - 生产敏感配置在服务器设置,不提交代码
- 敏感信息不用
-
命名规范
- 使用
NEXT_PUBLIC_前缀表示公开变量 - 使用大写字母和下划线:
DATABASE_URL
- 使用
-
调试技巧
- 修改后重启服务器
- 检查启动日志
- 使用 console.log 验证
-
团队协作
- 维护
.env.example文档 - 在 README 中说明环境变量配置
- 不提交
.env.local到版本控制
- 维护
相关资源
最后更新: 2025年11月24日