Next.js Environment Variable Structure
Next.js环境变量结构
Complete guide to Next.js environment variable management.
my-nextjs-app/
├── .env # Shared defaults (committed)
├── .env.local # Local secrets (gitignored)
├── .env.development # Development defaults (committed)
├── .env.development.local # Local dev overrides (gitignored)
├── .env.production # Production defaults (committed)
├── .env.production.local # Production secrets (gitignored)
├── .env.test # Test environment (committed)
└── .env.example # Documentation (committed)
my-nextjs-app/
├── .env # 共享默认配置(需提交至版本库)
├── .env.local # 本地密钥(需加入.gitignore忽略)
├── .env.development # 开发环境默认配置(需提交至版本库)
├── .env.development.local # 本地开发环境覆盖配置(需加入.gitignore忽略)
├── .env.production # 生产环境默认配置(需提交至版本库)
├── .env.production.local # 生产环境密钥(需加入.gitignore忽略)
├── .env.test # 测试环境配置(需提交至版本库)
└── .env.example # 配置文档(需提交至版本库)
Next.js loads files in this order (higher = higher precedence):
- (e.g., )
- (not loaded in test environment)
- (e.g., )
Example: In production, if
is defined in both
and
, the value from
wins.
Next.js按以下顺序加载文件(位置越靠上优先级越高):
- (例如:)
- (测试环境不加载)
- (例如:)
示例:在生产环境中,如果
同时在
和
中定义,则
中的值会生效。
Client-Side Variables (NEXT_PUBLIC_*)
客户端变量(NEXT_PUBLIC_*)
Exposed to the browser. Must prefix with
.
NEXT_PUBLIC_API_URL=
https://api.example.com
NEXT_PUBLIC_ANALYTICS_ID=UA-123456789
NEXT_PUBLIC_SITE_NAME=My Awesome Site
NEXT_PUBLIC_ENABLE_FEATURE_X=true
**Access in code**:
```javascript
// Works in both client and server
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
// Usage in components
export default function MyComponent() {
return <div>API: {process.env.NEXT_PUBLIC_API_URL}</div>;
}
⚠️ Security Warning: NEVER put secrets in
variables!
NEXT_PUBLIC_API_URL=
https://api.example.com
NEXT_PUBLIC_ANALYTICS_ID=UA-123456789
NEXT_PUBLIC_SITE_NAME=My Awesome Site
NEXT_PUBLIC_ENABLE_FEATURE_X=true
**代码中访问方式**:
```javascript
// 在客户端和服务端均可用
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
// 在组件中使用
export default function MyComponent() {
return <div>API: {process.env.NEXT_PUBLIC_API_URL}</div>;
}
❌ WRONG - Secret exposed to browser
❌ 错误 - 密钥会暴露至浏览器
NEXT_PUBLIC_API_SECRET=sk_live_abc123
NEXT_PUBLIC_API_SECRET=sk_live_abc123
✅ CORRECT - Secret only on server
✅ 正确 - 密钥仅在服务端可用
API_SECRET=sk_live_abc123
API_SECRET=sk_live_abc123
Server-Side Variables
服务端变量
Only available in server-side code (API routes, getServerSideProps, etc.).
仅在服务端代码中可用(API路由、getServerSideProps等)。
DATABASE_URL=postgres://localhost:5432/mydb
JWT_SECRET=super-secret-jwt-key-do-not-expose
STRIPE_SECRET_KEY=sk_live_abc123
SMTP_PASSWORD=email-password-here
**Access in code**:
```javascript
// ✅ Works in API routes
export default async function handler(req, res) {
const dbUrl = process.env.DATABASE_URL;
// Use dbUrl...
}
// ✅ Works in getServerSideProps
export async function getServerSideProps() {
const secret = process.env.JWT_SECRET;
// Use secret...
}
// ❌ Does NOT work in components (browser)
export default function MyComponent() {
const dbUrl = process.env.DATABASE_URL; // undefined!
}
DATABASE_URL=postgres://localhost:5432/mydb
JWT_SECRET=super-secret-jwt-key-do-not-expose
STRIPE_SECRET_KEY=sk_live_abc123
SMTP_PASSWORD=email-password-here
**代码中访问方式**:
```javascript
// ✅ 在API路由中可用
export default async function handler(req, res) {
const dbUrl = process.env.DATABASE_URL;
// 使用dbUrl...
}
// ✅ 在getServerSideProps中可用
export async function getServerSideProps() {
const secret = process.env.JWT_SECRET;
// 使用secret...
}
// ❌ 在组件中不可用(浏览器环境)
export default function MyComponent() {
const dbUrl = process.env.DATABASE_URL; // 结果为undefined!
}
.env (Committed - Shared Defaults)
.env(已提交 - 共享默认配置)
Shared defaults for all environments
所有环境共享的默认配置
NEXT_PUBLIC_APP_NAME=My Next.js App
NEXT_PUBLIC_DEFAULT_LOCALE=en
NEXT_PUBLIC_APP_NAME=My Next.js App
NEXT_PUBLIC_DEFAULT_LOCALE=en
Database (overridden in .env.local)
数据库配置(会被.env.local覆盖)
DATABASE_URL=postgres://localhost:5432/dev
DATABASE_URL=postgres://localhost:5432/dev
External services (no secrets)
外部服务配置(无密钥)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_abc123
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_abc123
.env.local (Gitignored - Local Secrets)
.env.local(已忽略 - 本地密钥)
Local development secrets
本地开发环境密钥
DATABASE_URL=postgres://localhost:5432/mylocal
JWT_SECRET=dev-jwt-secret-change-in-production
STRIPE_SECRET_KEY=sk_test_local_key
DATABASE_URL=postgres://localhost:5432/mylocal
JWT_SECRET=dev-jwt-secret-change-in-production
STRIPE_SECRET_KEY=sk_test_local_key
.env.production (Committed - Production Defaults)
.env.production(已提交 - 生产环境默认配置)
Production environment defaults
生产环境默认配置
These will be overridden by platform env vars
这些配置会被平台环境变量覆盖
DATABASE_URL=set-this-in-vercel
JWT_SECRET=set-this-in-vercel
DATABASE_URL=set-this-in-vercel
JWT_SECRET=set-this-in-vercel
.env.example (Committed - Documentation)
.env.example(已提交 - 配置文档)
Copy this to .env.local and fill in actual values
复制此文件为.env.local并填入实际值
Client-side (browser accessible)
客户端变量(可被浏览器访问)
NEXT_PUBLIC_API_URL=
https://api.example.com
NEXT_PUBLIC_ANALYTICS_ID=your-analytics-id
NEXT_PUBLIC_SITE_NAME=Your Site Name
NEXT_PUBLIC_API_URL=
https://api.example.com
NEXT_PUBLIC_ANALYTICS_ID=your-analytics-id
NEXT_PUBLIC_SITE_NAME=Your Site Name
Server-side (secrets)
服务端变量(密钥)
DATABASE_URL=postgres://user:password@host:5432/database # pragma: allowlist secret
JWT_SECRET=your-jwt-secret-32-chars-minimum
STRIPE_SECRET_KEY=sk_live_your_stripe_key
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-email@example.com
SMTP_PASSWORD=your-smtp-password
DATABASE_URL=postgres://user:password@host:5432/database # pragma: allowlist secret
JWT_SECRET=your-jwt-secret-32-chars-minimum
STRIPE_SECRET_KEY=sk_live_your_stripe_key
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-email@example.com
SMTP_PASSWORD=your-smtp-password
Database Configuration
数据库配置
Development (.env.local)
开发环境(.env.local)
DATABASE_URL=postgres://localhost:5432/myapp_dev
DATABASE_URL=postgres://localhost:5432/myapp_dev
Production (Vercel Environment Variables)
生产环境(Vercel环境变量)
DATABASE_URL=postgres://user:pass@prod-host:5432/myapp_prod # pragma: allowlist secret
DATABASE_URL=postgres://user:pass@prod-host:5432/myapp_prod # pragma: allowlist secret
Public keys (client-side)
公钥(客户端可用)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_abc123
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_abc123
Secret keys (server-side only)
密钥(仅服务端可用)
STRIPE_SECRET_KEY=sk_live_xyz789
STRIPE_SECRET_KEY=sk_live_xyz789
NEXT_PUBLIC_ENABLE_DARK_MODE=true
NEXT_PUBLIC_ENABLE_BETA_FEATURES=false
NEXT_PUBLIC_ENABLE_DARK_MODE=true
NEXT_PUBLIC_ENABLE_BETA_FEATURES=false
Deployment to Vercel
部署至Vercel
Step 1: Add Environment Variables in Vercel
步骤1:在Vercel中添加环境变量
- Go to Project Settings → Environment Variables
- Add each variable:
- Key:
- Value:
- Environments: Production, Preview, Development
Step 2: Separate Client vs Server Variables
步骤2:区分客户端与服务端变量
Vercel automatically exposes
variables at build time.
Vercel automatically handles:
Vercel会自动处理:
DATABASE_URL=postgres://... # ✅ Not exposed to browser
DATABASE_URL=postgres://... # ✅ 不会暴露至浏览器
Step 3: Rebuild After Changing NEXT_PUBLIC_ Variables
步骤3:修改NEXT_PUBLIC_变量后重新构建
⚠️ Important:
variables are
baked into the build at build time.
If changing them in Vercel, redeploy is required:
如果在Vercel中修改了这些变量,需要重新部署:
1. Validate Local Environment
1. 验证本地环境
python scripts/validate_env.py .env.local --framework nextjs
python scripts/validate_env.py .env.local --framework nextjs
Compare with .env.example
与.env.example对比
python scripts/validate_env.py .env.local --compare-with .env.example
python scripts/validate_env.py .env.local --compare-with .env.example
Check for security issues
检查安全问题
python scripts/scan_exposed.py --check-gitignore
python scripts/scan_exposed.py --check-gitignore
2. Check File Precedence
2. 检查文件优先级
List all .env files
列出所有.env文件
for file in .env*; do
echo "=== $file ==="
python scripts/validate_env.py $file --framework nextjs
done
for file in .env*; do
echo "=== $file ==="
python scripts/validate_env.py $file --framework nextjs
done
3. Sync to Vercel
3. 同步至Vercel
Compare local vs Vercel
对比本地与Vercel的变量
python scripts/sync_secrets.py --platform vercel --compare
python scripts/sync_secrets.py --platform vercel --compare
Sync (dry-run first)
同步(先进行试运行)
python scripts/sync_secrets.py --platform vercel --sync --dry-run
python scripts/sync_secrets.py --platform vercel --sync --dry-run
python scripts/sync_secrets.py --platform vercel --sync --confirm
python scripts/sync_secrets.py --platform vercel --sync --confirm
Issue: Variable Undefined in Browser
问题:变量在浏览器中显示为Undefined
Symptom:
is
in component.
Issue: Changed Variable Not Reflected
问题:修改变量后未生效
Symptom: Changed
variable in Vercel, but app still uses old value.
Solution: Redeploy (variables are baked into build):
症状:在Vercel中修改了
变量,但应用仍使用旧值。
解决方案:重新部署(变量在构建时已嵌入应用):
Issue: Works Locally, Not in Production
问题:本地正常运行,生产环境出错
Symptom: App works with
, fails in production.
Solution: Ensure all variables from
are set in Vercel:
症状:应用在本地使用
正常运行,但在生产环境中失败。
解决方案:确保
中的所有变量都已在Vercel中设置:
python scripts/sync_secrets.py --platform vercel --compare
python scripts/sync_secrets.py --platform vercel --compare
Find missing vars and add them in Vercel UI
找出缺失的变量并在Vercel界面中添加
Related: validation.md | security.md | frameworks.md
相关文档:validation.md | security.md | frameworks.md
When using Nextjs, these skills enhance your workflow:
- react: Core React patterns and hooks for Next.js components
- tanstack-query: Server-state management with App Router and Server Components
- drizzle: Type-safe ORM for Next.js server actions and API routes
- prisma: Alternative ORM with excellent Next.js integration
- test-driven-development: Testing Next.js App Router, Server Components, and API routes
[Full documentation available in these skills if deployed in your bundle]
使用Next.js时,以下技能可提升你的工作流:
- react:Next.js组件的核心React模式与钩子
- tanstack-query:App Router与Server Components的服务端状态管理
- drizzle:适用于Next.js服务端操作与API路由的类型安全ORM
- prisma:与Next.js集成良好的替代ORM
- test-driven-development:测试Next.js App Router、Server Components与API路由
[如果部署在你的技能包中,可查看完整文档]