如何配置环境变量?NEXTPUBLIC 前缀的作用是什么?
环境变量配置
1. 环境变量文件
Next.js 支持多种环境变量文件,按优先级排序:
# .env.local (最高优先级,所有环境)
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-secret-key
API_URL=http://localhost:3001
# .env.development (开发环境)
DEBUG=true
LOG_LEVEL=debug
# .env.production (生产环境)
DEBUG=false
LOG_LEVEL=error
# .env (默认,所有环境)
NODE_ENV=development
2. 环境变量类型
# .env.local
# 服务器端环境变量
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-super-secret-jwt-key
API_SECRET_KEY=your-api-secret-key
# 客户端环境变量 (NEXT_PUBLIC_ 前缀)
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_NAME=My App
NEXT_PUBLIC_VERSION=1.0.0
# 构建时环境变量
NEXT_PUBLIC_BUILD_TIME=2024-01-01
NEXT_PUBLIC_GIT_COMMIT=abc123
NEXTPUBLIC 前缀的作用
1. 客户端可访问性
// 服务器端环境变量 - 只在服务器端可用
// .env.local
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-secret-key
// 客户端环境变量 - 在客户端和服务器端都可用
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_NAME=My App
// 服务器端组件 - 可以访问所有环境变量
// app/api/users/route.js
export async function GET() {
// ✅ 可以访问服务器端环境变量
const dbUrl = process.env.DATABASE_URL
const jwtSecret = process.env.JWT_SECRET
// ✅ 也可以访问客户端环境变量
const apiUrl = process.env.NEXT_PUBLIC_API_URL
return NextResponse.json({ message: 'Hello' })
}
// 客户端组件 - 只能访问 NEXT_PUBLIC_ 前缀的变量
;('use client')
export default function ClientComponent() {
// ❌ 无法访问服务器端环境变量
// const dbUrl = process.env.DATABASE_URL // undefined
// ✅ 可以访问客户端环境变量
const apiUrl = process.env.NEXT_PUBLIC_API_URL
const appName = process.env.NEXT_PUBLIC_APP_NAME
return (
<div>
<h1>{appName}</h1>
<p>API URL: {apiUrl}</p>
</div>
)
}
2. 构建时替换
// 构建时,NEXT_PUBLIC_ 变量会被替换为实际值
// 客户端代码
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// 构建后的代码 (如果 NEXT_PUBLIC_API_URL=https://api.example.com)
const apiUrl = 'https://api.example.com'
实际应用示例
1. 多环境配置
# .env.development
NEXT_PUBLIC_API_URL=http://localhost:3001
NEXT_PUBLIC_APP_NAME=My App (Dev)
DEBUG=true
# .env.production
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_NAME=My App
DEBUG=false
# .env.staging
NEXT_PUBLIC_API_URL=https://staging-api.example.com
NEXT_PUBLIC_APP_NAME=My App (Staging)
DEBUG=true
// lib/config.js
export const config = {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
appName: process.env.NEXT_PUBLIC_APP_NAME,
debug: process.env.DEBUG === 'true',
isDevelopment: process.env.NODE_ENV === 'development',
isProduction: process.env.NODE_ENV === 'production',
}
2. 客户端配置
// app/components/ConfigProvider.jsx
'use client'
import { createContext, useContext } from 'react'
const ConfigContext = createContext()
export function ConfigProvider({ children }) {
const config = {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
appName: process.env.NEXT_PUBLIC_APP_NAME,
version: process.env.NEXT_PUBLIC_VERSION,
buildTime: process.env.NEXT_PUBLIC_BUILD_TIME,
}
return (
<ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>
)
}
export function useConfig() {
const context = useContext(ConfigContext)
if (!context) {
throw new Error('useConfig must be used within ConfigProvider')
}
return context
}
// app/components/ApiClient.jsx
'use client'
import { useConfig } from './ConfigProvider'
export function ApiClient() {
const { apiUrl } = useConfig()
const fetchData = async () => {
const response = await fetch(`${apiUrl}/data`)
return response.json()
}
return (
<div>
<p>API URL: {apiUrl}</p>
<button onClick={fetchData}>Fetch Data</button>
</div>
)
}
3. 服务器端配置
// lib/server-config.js
export const serverConfig = {
databaseUrl: process.env.DATABASE_URL,
jwtSecret: process.env.JWT_SECRET,
apiSecretKey: process.env.API_SECRET_KEY,
nodeEnv: process.env.NODE_ENV,
}
// 验证必需的环境变量
const requiredEnvVars = ['DATABASE_URL', 'JWT_SECRET', 'API_SECRET_KEY']
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`)
}
}
// app/api/config/route.js
import { serverConfig } from '@/lib/server-config'
export async function GET() {
// 只返回客户端需要的配置
return NextResponse.json({
apiUrl: process.env.NEXT_PUBLIC_API_URL,
appName: process.env.NEXT_PUBLIC_APP_NAME,
version: process.env.NEXT_PUBLIC_VERSION,
})
}
高级配置
1. 动态环境变量
// next.config.js
const nextConfig = {
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
BUILD_TIME: new Date().toISOString(),
},
publicRuntimeConfig: {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
appName: process.env.NEXT_PUBLIC_APP_NAME,
},
serverRuntimeConfig: {
secret: process.env.JWT_SECRET,
databaseUrl: process.env.DATABASE_URL,
},
}
2. 环境变量验证
// lib/env-validation.js
import { z } from 'zod'
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
NEXT_PUBLIC_API_URL: z.string().url(),
NEXT_PUBLIC_APP_NAME: z.string().min(1),
})
export const env = envSchema.parse(process.env)
3. 条件环境变量
// lib/conditional-env.js
export const getApiUrl = () => {
if (process.env.NODE_ENV === 'production') {
return process.env.NEXT_PUBLIC_API_URL
}
if (process.env.NODE_ENV === 'development') {
return process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'
}
return 'http://localhost:3001'
}
export const getDatabaseUrl = () => {
if (process.env.NODE_ENV === 'test') {
return process.env.TEST_DATABASE_URL
}
return process.env.DATABASE_URL
}
最佳实践
1. 环境变量组织
# .env.example (模板文件)
# 服务器端环境变量
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-secret-key
API_SECRET_KEY=your-api-secret-key
# 客户端环境变量
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_NAME=My App
NEXT_PUBLIC_VERSION=1.0.0
# 可选环境变量
DEBUG=false
LOG_LEVEL=info
2. 类型安全
// types/env.d.ts
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production' | 'test'
DATABASE_URL: string
JWT_SECRET: string
API_SECRET_KEY: string
NEXT_PUBLIC_API_URL: string
NEXT_PUBLIC_APP_NAME: string
NEXT_PUBLIC_VERSION: string
}
}
3. 安全考虑
// lib/secure-env.js
export const getSecureEnv = () => {
// 检查是否在客户端
if (typeof window !== 'undefined') {
// 客户端只能访问 NEXT_PUBLIC_ 变量
return {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
appName: process.env.NEXT_PUBLIC_APP_NAME,
}
}
// 服务器端可以访问所有变量
return {
databaseUrl: process.env.DATABASE_URL,
jwtSecret: process.env.JWT_SECRET,
apiSecretKey: process.env.API_SECRET_KEY,
apiUrl: process.env.NEXT_PUBLIC_API_URL,
appName: process.env.NEXT_PUBLIC_APP_NAME,
}
}
总结
环境变量配置要点:
文件优先级:
.env.local(最高优先级).env.development/.env.production.env(默认)
NEXTPUBLIC 前缀:
- 客户端可访问
- 构建时替换
- 公开可见
最佳实践:
- 使用
.env.example模板 - 验证必需的环境变量
- 区分客户端和服务器端变量
- 使用类型安全
- 注意安全性
安全考虑:
- 敏感信息不要使用
NEXT_PUBLIC_前缀 - 客户端环境变量是公开的
- 使用服务器端环境变量存储敏感信息