//
Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Configure e use variáveis de ambiente com segurança no Next.js 15+ com arquivos .env, o prefixo NEXT_PUBLIC_ para exposição ao cliente, configuração em tempo de execução e o padrão server-only para evitar vazamento de segredos.
# .env.local (ignorado pelo git, substituições locais)
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
AUTH_SECRET="super-secret-key-never-expose"
# Variáveis seguras para o cliente devem usar o prefixo NEXT_PUBLIC_
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_abc123"# .env (verificado no git, padrões compartilhados)
NEXT_PUBLIC_APP_NAME="Meu App"# .env.production (substituições de produção)
NEXT_PUBLIC_APP_URL="https://myapp.com"// lib/env.ts
import "server-only";
function requireEnv(key: string): string {
const value = process.env[key];
if (!value) {
throw new Error(`Variável de ambiente obrigatória não encontrada: ${key}`);
}
return value;
}
export const env = {
DATABASE_URL: requireEnv("DATABASE_URL"),
AUTH_SECRET: requireEnv("AUTH_SECRET"),
} as const;// lib/env-client.ts
export const clientEnv = {
appUrl: process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000",
appName: process.env.NEXT_PUBLIC_APP_NAME ?? "Meu App",
stripeKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "",
} as const;// lib/env.ts
import "server-only";
import { z } from "zod";
const envSchema = z.object({
DATABASE_URL: z.string().url(),
AUTH_SECRET: z.string().min(32),
NODE_ENV: z.enum(["development", "production", "test"]),
});
export const env = envSchema.parse(process.env);
// lib/env-client.ts
const clientEnvSchema = z.object({
NEXT_PUBLIC_APP_URL: z.string().url(),
NEXT_PUBLIC_APP_NAME: z.string(),
});
export const clientEnv = clientEnvSchema.parse({
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
NEXT_PUBLIC_APP_NAME: process.env.NEXT_PUBLIC_APP_NAME,
});// app/dashboard/page.tsx
import { env } from "@/lib/env";
export default async function DashboardPage() {
// Seguro: isso é executado apenas no servidor
const data = await fetch(`${env.DATABASE_URL}/api/data`);
return <div>{/* renderizar dados */}</div>;
}.env automaticamente na seguinte ordem de prioridade (o maior vence): .env.$(NODE_ENV).local > .env.local > .env.$(NODE_ENV) > .env.NEXT_PUBLIC_ são incluídas no pacote do cliente em tempo de compilação. Todas as outras referências process.env são substituídas por undefined no código do cliente.process.env não é um objeto real no código do cliente. O Next.js realiza substituição estática de strings em tempo de compilação. Acesso dinâmico como process.env[key] não funcionará em componentes do cliente.server-only causa um erro em tempo de compilação se um módulo for importado de um Componente Cliente, fornecendo uma garantia rígida de que os segredos permanecem no servidor.serverRuntimeConfig / publicRuntimeConfig em next.config.js (padrão legado do Pages Router).Variáveis de Ambiente em Tempo de Execução (Docker):
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
// Expõe variáveis de ambiente do lado do servidor em tempo de execução (não em tempo de compilação)
serverRuntimeConfig: {
databaseUrl: process.env.DATABASE_URL,
},
// Expõe para servidor e cliente em tempo de execução
publicRuntimeConfig: {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
},
};
export default nextConfig;Usando T3 Env para Validação Completa:
// env.mjs
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
AUTH_SECRET: z.string().min(1),
},
client: {
NEXT_PUBLIC_APP_URL: z.string().url(),
},
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
AUTH_SECRET: process.env.AUTH_SECRET,
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
},
});env.d.ts para aumentar ProcessEnv para autocompletar:// env.d.ts
declare namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
AUTH_SECRET: string;
NEXT_PUBLIC_APP_URL: string;
NEXT_PUBLIC_APP_NAME: string;
}
}process.env[varName] será sempre undefined no cliente porque o Next.js realiza substituição estática de strings, não consulta em tempo de execução..env.local não é carregado em ambientes test por padrão. Use um arquivo .env.test.local ou carregue as variáveis de ambiente manualmente na configuração de seus testes..env requer reinicialização do servidor de desenvolvimento. O hot reload não capta as alterações nas variáveis de ambiente.NEXT_PUBLIC_ são visíveis no pacote do navegador. Nunca coloque segredos (chaves de API, URLs de banco de dados, segredos de autenticação) atrás deste prefixo.standalone e defina as variáveis de ambiente no contêiner em execução, não na etapa RUN do Dockerfile.| Abordagem | Prós | Contras |
|---|---|---|
Arquivos .env com NEXT_PUBLIC_ | Embutido, sem configuração | Sem validação, sem env em tempo de execução |
Validação Zod em lib/env.ts | Seguro em tipo, falha rápido | Configuração manual |
T3 Env (@t3-oss/env-nextjs) | Validação completa, divisão cliente/servidor | Dependência extra |
next.config.js runtimeConfig | Verdadeiro env em tempo de execução | Padrão legado, não nativo do App Router |
| Env da Plataforma (Vercel, AWS) | Seguro, por ambiente | Configuração específica do fornecedor |
process.env.NEXT_PUBLIC_APP_URL são substituídas.process.env[key]) não pode ser resolvido em tempo de compilação e retorna undefined..env.$(NODE_ENV).local (maior prioridade).env.local.env.$(NODE_ENV).env (menor prioridade).env.local é ignorado pelo git por padrão.NEXT_PUBLIC_..env.next dev para que as alterações entrem em vigor.server-only causa um erro em tempo de compilação se um Componente Cliente importar o módulo.NEXT_PUBLIC_ são sempre incorporadas em tempo de compilação e não podem ser alteradas em tempo de execução.docker run -e KEY=value).output: "standalone" para que as leituras de process.env ocorram em tempo de execução para o código do servidor..env.local quando NODE_ENV=test por padrão..env.test.local em vez disso, ou carregue manualmente os arquivos de ambiente em sua configuração de teste.// env.d.ts
declare namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
AUTH_SECRET: string;
NEXT_PUBLIC_APP_URL: string;
}
}ProcessEnv para que process.env.DATABASE_URL obtenha autocompletar..url(), .min(32)) e não apenas a presença.NEXT_PUBLIC_ são substituídos estaticamente em tempo de next build.NEXT_PUBLIC_ mudar.@t3-oss/env-nextjs) fornece uma única chamada createEnv que separa esquemas de servidor e cliente.NEXT_PUBLIC_ estão na seção client e as variáveis do servidor estão em server.import { z } from "zod";
const envSchema = z.object({
DATABASE_URL: z.string().url(),
AUTH_SECRET: z.string().min(32),
});
// O tipo é inferido automaticamente:
// { DATABASE_URL: string; AUTH_SECRET: string }
export const env = envSchema.parse(process.env);AUTH_SECRET com segurançaRevisado por Chris St. John·Última atualização: 7 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥