Dotenv e Variáveis de Ambiente: Como Usar com Segurança
Aprenda a usar Dotenv e variáveis de ambiente com segurança: configuração, validação, precedência, Next.js, Docker, CI/CD e produção sem vazamentos.

Dotenv e variáveis de ambiente ajudam a separar do código os valores que mudam entre computadores e deploys, como porta, endereço de banco, modo de execução e credenciais.
Em aplicações Node.js, o Dotenv lê pares de chave e valor de um arquivo .env e os disponibiliza em process.env.
Essa separação melhora a portabilidade, mas não transforma o arquivo .env em um cofre.
Se ele for enviado ao Git, incluído em uma imagem Docker, copiado para logs ou compartilhado sem controle, os valores podem vazar. Em produção, o ideal é injetar a configuração pelo ambiente de execução e usar um gerenciador de segredos quando o risco justificar.
Neste guia, você aprenderá a criar, carregar, validar e organizar variáveis de ambiente; entenderá precedência, Next.js, testes, Docker e CI/CD; e verá como reagir caso uma credencial seja exposta.
Os exemplos usam Node.js, mas os princípios se aplicam a muitas linguagens e plataformas.
O que são variáveis de ambiente?
Variáveis de ambiente são pares de nome e valor associados ao ambiente em que um processo é executado.
O sistema operacional, um terminal, um serviço de hospedagem, um contêiner ou uma pipeline pode fornecê-las antes de iniciar a aplicação. No Node.js, elas ficam acessíveis pelo objeto process.env.
Elas são adequadas para valores que mudam entre deploys: porta da aplicação, URL de uma API, endereço do banco, nome de um bucket, nível de log ou identificador de uma integração.
A metodologia Twelve-Factor App recomenda separar configuração e código para que o mesmo código possa ser implantado em ambientes diferentes sem edição.
Nem toda configuração precisa sair do código. Rotas internas, algoritmos e relações estáveis entre módulos pertencem à aplicação. Uma pergunta útil é: “este valor pode mudar de um deploy para outro?”. Se sim, ele é um bom candidato.
Se a resposta for não, transformá-lo em variável pode apenas esconder uma decisão de código.
O que o Dotenv faz — e o que não faz
O pacote Dotenv lê um arquivo, normalmente chamado .env, interpreta os pares de chave e valor e os adiciona a process.env. Isso facilita o desenvolvimento local, no qual cada pessoa pode manter sua configuração fora do código versionado.
Ele não criptografa o arquivo, não controla quem o copia, não rotaciona credenciais e não impede que a aplicação escreva um segredo no log.
Também não altera automaticamente variáveis já presentes no ambiente: por padrão, um valor fornecido pelo sistema ou pela plataforma permanece, e a chave equivalente do .env é ignorada.
Essa distinção evita uma falsa sensação de segurança. Dotenv é um carregador de configuração.
Controle de acesso, auditoria, expiração e rotação pertencem a outra camada, aprofundada no guia de gerenciamento de segredos.
Como instalar e carregar Dotenv no Node.js
Em um projeto Node.js, instale o pacote como dependência da aplicação. Carregue-o antes de importar módulos que leem variáveis durante a inicialização.
Se um cliente de banco for criado antes do carregamento, ele poderá capturar um valor indefinido e continuar incorreto mesmo depois de process.env ser preenchido.
npm install dotenv
CommonJS
require('dotenv').config()
const port = process.env.PORT
console.log(`Aplicação configurada na porta ${port}`)
O método config() procura .env no diretório de trabalho atual. Em monorepos ou scripts executados de pastas diferentes, declare o caminho conscientemente em vez de depender de uma coincidência.
Evite imprimir o objeto retornado em ambientes compartilhados, pois ele pode conter valores sensíveis.
ES Modules
import 'dotenv/config'
import { iniciarServidor } from './servidor.js'
iniciarServidor()
Imports ES Modules são avaliados antes do corpo do módulo atual. Por isso, chamar dotenv.config() e depois usar um import estático que já leu process.env pode ser tarde demais.
Importar dotenv/config primeiro ou usar um módulo inicializador dedicado torna a ordem explícita.
Se você ainda está estruturando uma API, o artigo sobre Node.js para back-end ajuda a conectar módulos, servidor, entrada e saída antes de adicionar configuração por ambiente.
Suporte nativo do Node.js a arquivos .env
Versões atuais do Node.js oferecem suporte estável a arquivos .env. A documentação oficial de variáveis de ambiente do Node.js descreve a opção --env-file, além das APIs process.loadEnvFile e util.parseEnv. Para projetos simples, isso pode eliminar uma dependência.
node --env-file=.env src/servidor.js
Não migre apenas para “usar o mais novo”. Confira a versão mínima do runtime, o formato dos arquivos, o comportamento de precedência e a plataforma de deploy.
Uma equipe com runtimes diferentes pode preferir Dotenv até padronizar a execução.
Sintaxe correta de um arquivo .env
PORT=3000
APP_MODE=development
DATABASE_URL="postgresql://usuario:senha-local@localhost:5432/app"
LOG_LEVEL=info
# Comentário de documentação local
Use nomes previsíveis, normalmente em letras maiúsculas e separados por sublinhado. O Node.js aceita letras, dígitos e sublinhados, mas o nome não pode começar por número.
Espaços ao redor do nome e do sinal de igualdade podem ser ignorados por alguns parsers, porém um estilo consistente reduz surpresas entre ferramentas.
Aspas são úteis quando o valor contém espaços, cerquilha ou quebras de linha. Sem aspas, uma cerquilha pode iniciar comentário.
Não suponha que expansão de outras variáveis, substituição de comandos ou sintaxe de shell funcionará igual em todos os parsers; consulte a ferramenta usada pelo projeto.
Todos os valores chegam como texto
Em process.env, "3000", "true" e "null" são strings. Usar Boolean(process.env.DEBUG) é perigoso: qualquer string não vazia, inclusive "false", vira verdadeiro. Converta e valide cada tipo explicitamente.
Use .env.example sem segredos
O arquivo real deve entrar no .gitignore. Já um .env.example pode ser versionado para documentar as chaves necessárias, usando valores vazios ou exemplos inofensivos.
Assim, uma pessoa nova entende o contrato de configuração sem receber credenciais por mensagem.
# .env.example
PORT=3000
DATABASE_URL=
EMAIL_PROVIDER_API_KEY=
LOG_LEVEL=info
O exemplo deve acompanhar o código. Ao adicionar ou remover uma variável obrigatória, atualize o arquivo, a validação e a documentação no mesmo pull request.
Não coloque uma credencial “de teste” supondo que ela não importa; ambientes de teste também podem conter dados, permissões ou custos.
Precedência: qual valor vence?
Uma aplicação pode receber a mesma chave de várias fontes: sistema operacional, orquestrador, comando de execução, plataforma de hospedagem e arquivo local.
Defina e documente uma regra. No Dotenv, uma variável já definida em process.env não é sobrescrita por padrão. Isso permite que a plataforma de produção tenha prioridade sobre o arquivo.
A opção override muda esse comportamento, mas deve ser adotada conscientemente. Sobrescrever silenciosamente uma configuração injetada pelo ambiente pode apontar um serviço para o banco errado.
Em múltiplos arquivos, a ordem de carregamento também importa e varia conforme a ferramenta ou framework.

Valide a configuração ao iniciar
Não espalhe leituras de process.env por toda a aplicação. Crie um módulo de configuração que leia, converta e valide os valores uma única vez.
Se uma chave obrigatória estiver ausente, encerre a inicialização com uma mensagem que informe o nome da chave, nunca seu conteúdo.
function obrigatoria(nome) {
const valor = process.env[nome]
if (!valor) throw new Error(`Variável obrigatória ausente: ${nome}`)
return valor
}
export const config = Object.freeze({
databaseUrl: obrigatoria('DATABASE_URL'),
emailApiKey: obrigatoria('EMAIL_PROVIDER_API_KEY'),
})
Falhar cedo é melhor do que descobrir a ausência durante uma requisição real. Para projetos maiores, bibliotecas de schema podem declarar formato, padrão, intervalo e mensagens.
Ainda assim, a equipe deve compreender o contrato e evitar que a validação mostre o segredo em erros, telemetria ou snapshots de teste.
Conversão segura de tipos
const port = Number(process.env.PORT ?? '3000')
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new Error('PORT deve ser um inteiro válido')
}
const debug = process.env.DEBUG === 'true'
Para URLs, use o construtor URL; para listas, defina separador e tratamento de espaços; para JSON, capture erros de parsing. Valores padrão são adequados quando existe uma escolha realmente segura.
Uma credencial obrigatória não deve ganhar um padrão fictício que permita a aplicação iniciar e falhar depois.
Desenvolvimento, teste e produção
Cada deploy deve receber seus próprios valores. Desenvolvimento pode apontar para serviços locais; testes automatizados usam recursos isolados; homologação se aproxima da produção sem compartilhar credenciais; produção restringe acesso e privilegia injeção pela plataforma. Reutilizar a mesma senha entre ambientes amplia o impacto de um vazamento.
Arquivos como .env.test ou .env.local podem organizar o trabalho, desde que a ordem seja explícita e os arquivos sensíveis não sejam versionados. Evite uma cadeia complicada de herança.
Quanto mais fontes implícitas, mais difícil reproduzir por que um valor venceu.
Nos testes, salve e restaure as variáveis alteradas ou execute cada suíte em um processo isolado. Nunca permita que um teste local use por acidente a URL do banco de produção.
Uma verificação de nome do banco, host e modo de execução pode bloquear esse cenário antes de apagar ou modificar dados reais.
Variáveis de ambiente no Next.js
O Next.js já carrega arquivos .env e define uma ordem própria. Segundo a documentação oficial de variáveis de ambiente do Next.js, valores sem o prefixo público ficam disponíveis no ambiente do servidor.
Em muitos projetos, instalar Dotenv manualmente dentro da aplicação é redundante.
Servidor e navegador não são o mesmo ambiente
Uma variável com prefixo NEXT_PUBLIC_ pode ser incorporada ao JavaScript enviado ao navegador durante o build. Portanto, ela é pública. Nunca use esse prefixo em senha, token privado ou chave capaz de executar operações protegidas.
Mesmo que o arquivo permaneça fora do Git, o valor aparecerá para quem baixar o bundle.
Variáveis públicas são adequadas para identificadores que foram projetados para exposição, como uma URL pública ou um ID de analytics. Para segredos, mantenha o acesso em Server Components, Route Handlers ou serviços de back-end.
O guia de desenvolvimento de APIs mostra como manter autenticação, autorização e integrações na fronteira correta.
Também diferencie build e runtime. Variáveis públicas injetadas no build podem ficar congeladas no artefato.
Se a mesma imagem for promovida entre ambientes, um valor de homologação pode seguir dentro do bundle. Defina quais chaves são avaliadas durante a construção e quais precisam ser lidas quando o servidor executa.
Docker: configuração no build e no runtime
Não copie .env para a imagem Docker. Adicione o arquivo ao .dockerignore e injete valores no momento da execução por meio da plataforma, do orquestrador ou de um mecanismo de secrets.
Gravar credenciais com ENV ou ARG no Dockerfile pode deixá-las em camadas, histórico ou metadados do build.
# .dockerignore
.env
.env.*
!.env.example
Um arquivo local pode ser passado para um contêiner de desenvolvimento sem ser incorporado à imagem, mas permissões e destino ainda precisam ser controlados.
Em produção, prefira que a infraestrutura injete somente as chaves necessárias para aquele serviço. Para revisar imagens, camadas e execução, consulte o guia Docker Descomplicado.
Como usar em CI/CD e produção
Na pipeline, armazene credenciais no recurso de secrets da plataforma e limite a disponibilidade por repositório, ambiente, branch e etapa. Um job de lint não precisa da senha do banco.
Um build de front-end não deve receber uma chave exclusiva do servidor. Aplique o menor privilégio possível.
Evite comandos que imprimam o ambiente completo e desative debug excessivo em ferramentas que exibem parâmetros. Mascaramento de log é uma barreira adicional, não uma garantia: valores transformados, divididos ou codificados podem escapar.
Revise também artefatos, relatórios de erro, arquivos de cache e imagens de contêiner.
O artigo de CI/CD com segurança aprofunda ambientes protegidos, OIDC, artefatos imutáveis e rollback. Sempre que possível, use identidades temporárias em vez de chaves estáticas de longa duração.

Dotenv não substitui gerenciamento de segredos
Variáveis de ambiente são um canal de entrega, não necessariamente um armazenamento seguro. A OWASP Secrets Management Cheat Sheet alerta que variáveis podem ser acessadas por processos, aparecer em logs ou dumps e devem ser usadas com consciência das limitações.
Um gerenciador de segredos adiciona controles como autenticação do workload, políticas, auditoria, versionamento, rotação e revogação. A aplicação pode buscar o valor no início ou recebê-lo montado em memória ou arquivo temporário.
A escolha depende do provedor, do risco e da necessidade de atualizar a credencial sem reiniciar o serviço.
Não coloque todos os valores no mesmo pacote. Uma URL pública não exige o mesmo tratamento de uma chave privada. Classifique a configuração, limite acesso por serviço e mantenha o código capaz de iniciar somente quando as dependências necessárias estiverem disponíveis.
O que fazer se um segredo vazar
- Revogue ou rotacione a credencial: remover o arquivo do último commit não invalida cópias já feitas.
- Reduza o impacto: suspenda integrações ou limite permissões quando a rotação não for imediata.
- Investigue o uso: consulte logs do provedor e procure acessos, custos ou alterações inesperadas.
- Remova o material do repositório e do histórico: faça isso depois de invalidar o segredo e coordene a reescrita com a equipe.
- Procure outras cópias: pipelines, artefatos, imagens, logs, backups, mensagens e forks podem reter o valor.
- Corrija a origem: atualize
.gitignore, validações, proteção de push e processo de distribuição. - Documente o incidente: registre alcance, resposta e ações preventivas sem repetir o segredo.
Considere qualquer segredo publicado como comprometido, mesmo que o repositório tenha ficado público por pouco tempo. Sistemas automáticos monitoram commits e pacotes. A primeira ação é tornar a credencial inútil; “apagar da tela” vem depois.
Erros comuns com Dotenv
- Carregar depois dos módulos dependentes: valores são lidos antes de o Dotenv preencher
process.env. - Versionar o arquivo real:
.enventra no Git e passa a existir no histórico. - Confiar somente no .gitignore: arquivos já rastreados continuam sendo enviados até serem removidos do índice.
- Usar Boolean em strings:
Boolean("false")resulta em verdadeiro. - Expor segredo no front-end: prefixos públicos e valores de build chegam ao navegador.
- Imprimir process.env: logs e relatórios acabam armazenando credenciais.
- Copiar .env para Docker: o segredo permanece dentro da imagem ou de suas camadas.
- Não validar: a aplicação inicia com uma URL vazia e falha durante o uso.
- Compartilhar uma chave entre ambientes: o vazamento de desenvolvimento compromete produção.
- Confundir configuração com segredo: tudo recebe o mesmo controle, dificultando uso e revisão.
Checklist para usar variáveis com segurança
- O arquivo
.envreal está no.gitignoree no.dockerignore? - O repositório mantém apenas um
.env.examplesem valores sensíveis? - Dotenv ou o carregador nativo executa antes dos módulos que leem a configuração?
- A ordem de precedência está documentada?
- Variáveis obrigatórias e tipos são validados no início?
- Mensagens de erro informam a chave sem revelar o valor?
- Segredos do servidor nunca recebem prefixos públicos do framework?
- Builds, logs, artefatos e imagens foram verificados contra vazamentos?
- Cada ambiente usa credenciais próprias e com menor privilégio?
- A pipeline entrega somente os segredos necessários a cada job?
- Produção usa injeção do ambiente ou gerenciador de segredos em vez de arquivo versionado?
- Existe um procedimento de rotação e resposta a vazamentos?
Perguntas frequentes
Devo enviar o arquivo .env para o Git?
Em geral, não. Ignore arquivos reais e versione somente um .env.example sem segredos. Se um arquivo já entrou no histórico, adicionar ao .gitignore não resolve sozinho: invalide as credenciais, remova o rastreamento e trate as cópias históricas.
Dotenv é necessário nas versões atuais do Node.js?
Nem sempre. O Node.js atual possui suporte nativo a arquivos .env. Dotenv continua útil para compatibilidade com versões anteriores, APIs conhecidas e opções específicas. A decisão deve considerar o runtime mínimo e o comportamento exigido, não apenas a possibilidade de remover uma dependência.
Variável de ambiente é sempre segura?
Não. Dependendo do sistema, processos, logs, dumps, painéis administrativos e ferramentas de observabilidade podem expor valores. Use permissões mínimas, evite logar o ambiente e prefira identidades temporárias ou um gerenciador de segredos para credenciais importantes.
Conclusão
Dotenv simplifica a configuração local ao carregar um arquivo .env em process.env.
O uso responsável exige mais: ignorar arquivos sensíveis, manter um exemplo seguro, definir precedência, validar tipos, separar servidor e navegador e impedir que segredos entrem no build, nos logs ou no repositório.
Em produção, trate variáveis como parte do contrato de deploy e segredos como ativos com ciclo de vida.
Injete apenas o necessário, aplique menor privilégio e esteja preparado para rotacionar. Assim, o mesmo código atravessa desenvolvimento, teste e produção com configuração previsível e risco menor.