--env-file e process.loadEnvFile(): Arquivos .env Nativos no Node.js

Como carregar variáveis de arquivos .env sem o pacote dotenv usando a flag --env-file, a variante --env-file-if-exists e as funções process.loadEnvFile() e util.parseEnv() do Node.js.

Carregar variáveis de um arquivo .env é tão comum que o pacote dotenv virou dependência quase obrigatória em projetos Node.js. Hoje o próprio runtime faz isso: a flag --env-file carrega o arquivo antes da aplicação iniciar, e a função process.loadEnvFile() faz o mesmo de dentro do código, sem instalar nada.

O jeito antigo

Com o dotenv, o primeiro passo de toda aplicação era instalar o pacote e chamá-lo antes de qualquer outro import que dependesse das variáveis:

// npm install dotenv
import 'dotenv/config';

console.log(process.env.DATABASE_URL);

Funciona, mas é mais uma dependência para manter atualizada e auditar, e a ordem dos imports vira uma armadilha: qualquer módulo carregado antes do dotenv não enxerga as variáveis.

--env-file: variáveis carregadas antes do código

Com a flag --env-file, o Node lê o arquivo e popula process.env antes de executar a primeira linha da aplicação. Dado este .env:

# .env
PORT=3000
DATABASE_URL="postgres://app:segredo@localhost:5432/loja"
export LOG_LEVEL=debug # o "export" no início é ignorado

basta apontar o arquivo na linha de comando:

node --env-file=.env server.js
// server.js
import http from 'node:http';

const porta = Number(process.env.PORT);

http.createServer((req, res) => {
    res.end(`Nível de log: ${process.env.LOG_LEVEL}`);
}).listen(porta, () => console.log(`Rodando na porta ${porta}`));

O formato aceita comentários com #, valores entre aspas simples, duplas ou crases, o prefixo export e valores de múltiplas linhas entre aspas.

Vários arquivos e arquivos opcionais

A flag pode ser repetida. Arquivos posteriores sobrescrevem variáveis definidas pelos anteriores, o que facilita ter uma base comum e um ajuste por ambiente:

node --env-file=.env --env-file=.env.local server.js

Se o arquivo não existir, --env-file encerra com erro. Para arquivos que podem ou não estar presentes — como um .env.local que só existe na máquina de quem desenvolve — use --env-file-if-exists:

node --env-file=.env --env-file-if-exists=.env.local server.js

Um detalhe importante: se a mesma variável já existir no ambiente do processo (definida pelo shell, pelo Docker ou pela plataforma de deploy), o valor do ambiente vence o do arquivo. Assim, o .env serve de valor padrão e a produção pode sobrescrevê-lo sem mexer em nada.

process.loadEnvFile(): carregando de dentro do código

Quando não dá para controlar a linha de comando — por exemplo, num script chamado por outra ferramenta — process.loadEnvFile() carrega o arquivo em tempo de execução. Sem argumentos, ele lê o .env do diretório atual:

// migrar.js
if (process.env.NODE_ENV === 'test') {
    process.loadEnvFile('./.env.test'); // carregado primeiro, tem prioridade
}

process.loadEnvFile(); // completa com o que faltar do ./.env

console.log(`Migrando o banco ${process.env.DATABASE_URL}`);

Assim como a flag, process.loadEnvFile() não sobrescreve variáveis que já existem em process.env — nem as do ambiente, nem as carregadas por uma chamada anterior. Por isso a ordem importa: no exemplo, o .env.test é carregado antes, e o .env só preenche as variáveis que ainda faltam.

Para apenas interpretar o conteúdo sem tocar em process.env, existe util.parseEnv(), que transforma o texto de um .env em um objeto:

import { parseEnv } from 'node:util';

const vars = parseEnv('API_URL=https://api.exemplo.com\nTIMEOUT=5000');
console.log(vars); // { API_URL: 'https://api.exemplo.com', TIMEOUT: '5000' }

Usando no package.json

{
  "scripts": {
    "dev": "node --watch --env-file=.env --env-file-if-exists=.env.local server.js",
    "start": "node --env-file-if-exists=.env server.js"
  }
}

No script start, o --env-file-if-exists permite que o mesmo comando funcione em produção, onde as variáveis normalmente vêm da plataforma e não existe .env.

Quando usar

Cuidados

O suporte nativo cobre a leitura do arquivo, mas não recursos extras de bibliotecas como dotenv-expand, como referenciar uma variável dentro de outra (${HOST}:${PORT}). Continue mantendo o .env fora do controle de versão e lembre que todos os valores chegam como string — converta números e booleanos explicitamente.

Compatibilidade

A flag --env-file chegou no Node.js 20.6.0. process.loadEnvFile() e util.parseEnv() vieram no Node.js 21.7.0, com backport para o 20.12.0, e --env-file-if-exists no Node.js 22.9.0. As flags --env-file e --env-file-if-exists deixaram de ser experimentais no Node.js 24.10.0 e 22.21.0.

documentação oficial

Conclusão

Com --env-file, --env-file-if-exists e process.loadEnvFile(), o Node.js resolve sozinho o que antes exigia o dotenv. A regra de que o ambiente sempre vence o arquivo deixa o mesmo código funcionar no desenvolvimento e em produção, com uma dependência a menos para manter.

Tecnologia:
node

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.