Variáveis de ambiente com dotenv
1. Introdução às variáveis de ambiente
Variáveis de ambiente são pares chave-valor armazenados no sistema operacional ou em arquivos de configuração, que influenciam o comportamento de aplicações em tempo de execução. Em projetos JavaScript, elas são essenciais para separar configurações sensíveis do código-fonte.
O principal problema que resolvem é a segurança: senhas de banco de dados, chaves de API, tokens JWT e outras credenciais não devem jamais ser escritas diretamente no código. Se um repositório for comprometido ou tornado público, esses dados ficam expostos. Além disso, variáveis de ambiente permitem que diferentes ambientes (desenvolvimento, teste, produção) usem configurações distintas sem alterar o código.
O arquivo .env tornou-se o padrão de facto para gerenciar essas variáveis em projetos Node.js, e a biblioteca dotenv é a ferramenta mais utilizada para carregá-las automaticamente.
2. Instalação e configuração básica do dotenv
A instalação é simples via npm:
npm install dotenv
No arquivo principal da aplicação (geralmente index.js, app.js ou server.js), adicione o carregamento automático:
require('dotenv').config();
// Restante da aplicação
const express = require('express');
const app = express();
O arquivo .env deve estar na raiz do projeto com a seguinte sintaxe:
PORT=3000
DB_HOST=localhost
DB_USER=admin
DB_PASS=senha_segura
JWT_SECRET=minha_chave_secreta
Importante: não use aspas nos valores. Se precisar de espaços, o valor deve ser mantido sem aspas — o dotenv lida com isso automaticamente.
3. Acessando variáveis de ambiente no Node.js
Após configurar o dotenv, as variáveis ficam disponíveis em process.env:
const port = process.env.PORT;
const dbHost = process.env.DB_HOST;
console.log(`Servidor rodando na porta ${port}`);
Para valores padrão (fallback), use o operador ||:
const port = process.env.PORT || 3000;
Como tudo é string, é necessário converter tipos:
// Número
const port = Number(process.env.PORT) || 3000;
// Booleano
const isDev = process.env.NODE_ENV === 'development';
// JSON
const config = JSON.parse(process.env.APP_CONFIG || '{}');
4. Boas práticas com dotenv em projetos Node.js + Express
Em aplicações Express, é comum organizar variáveis por ambiente:
// .env.development
PORT=3000
DB_URL=mongodb://localhost:27017/dev_db
JWT_SECRET=dev_secret_key
// .env.production
PORT=8080
DB_URL=mongodb://prod-server:27017/prod_db
JWT_SECRET=prod_secret_key_super_segura
Carregue o arquivo correto baseado no ambiente:
const path = require('path');
const envFile = process.env.NODE_ENV === 'production'
? '.env.production'
: '.env.development';
require('dotenv').config({ path: path.resolve(__dirname, '..', envFile) });
Exemplo prático completo com Express + PostgreSQL + JWT:
require('dotenv').config();
const express = require('express');
const { Pool } = require('pg');
const jwt = require('jsonwebtoken');
const app = express();
const port = process.env.PORT || 3000;
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
});
app.post('/login', async (req, res) => {
const token = jwt.sign(
{ userId: 123 },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN || '1h' }
);
res.json({ token });
});
app.listen(port, () => {
console.log(`Servidor rodando na porta ${port}`);
});
5. Integração com React (Create React App e Vite)
No frontend React, as variáveis de ambiente funcionam de forma diferente. Create React App exige o prefixo REACT_APP_:
// .env (na raiz do projeto CRA)
REACT_APP_API_URL=https://api.exemplo.com
REACT_APP_GOOGLE_CLIENT_ID=123456789
No código React:
const apiUrl = process.env.REACT_APP_API_URL;
const googleClientId = process.env.REACT_APP_GOOGLE_CLIENT_ID;
Com Vite, o prefixo é VITE_:
// .env
VITE_API_URL=https://api.exemplo.com
// Código React
const apiUrl = import.meta.env.VITE_API_URL;
Diferença crucial: variáveis de ambiente do lado do cliente (React) são injetadas em tempo de build e ficam visíveis no bundle final. Já no Node.js (backend), são lidas em tempo de execução e permanecem no servidor. Nunca coloque chaves secretas de backend em variáveis REACT_APP_ ou VITE_.
Para compartilhar variáveis comuns (como URL da API), crie um arquivo .env na raiz do monorepo e referencie-o em ambos os projetos.
6. Segurança e versionamento
O passo mais importante: adicione .env ao .gitignore:
# .gitignore
.env
.env.*.local
Crie um arquivo .env.example como template para outros desenvolvedores:
# .env.example
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
JWT_SECRET=your_secret_key_here
NODE_ENV=development
Valide variáveis obrigatórias na inicialização:
const requiredVars = ['DATABASE_URL', 'JWT_SECRET', 'PORT'];
requiredVars.forEach(varName => {
if (!process.env[varName]) {
throw new Error(`Variável obrigatória ${varName} não definida`);
}
});
7. Depuração e troubleshooting
Para verificar se o dotenv carregou corretamente:
const result = require('dotenv').config();
if (result.error) {
console.error('Erro ao carregar .env:', result.error);
} else {
console.log('.env carregado com sucesso');
}
Problemas comuns:
- Caminho incorreto: use path.resolve(__dirname, '.env') para garantir o caminho absoluto
- Sobrescrita: variáveis já existentes no sistema não são sobrescritas por padrão. Use override: true se necessário
- Encoding: arquivos .env devem ser salvos em UTF-8 sem BOM
Para interpolação de variáveis (ex: DB_URL=mongodb://${DB_USER}:${DB_PASS}@localhost), instale dotenv-expand:
npm install dotenv-expand
const dotenv = require('dotenv');
const dotenvExpand = require('dotenv-expand');
dotenvExpand.expand(dotenv.config());
8. Alternativas e considerações finais
Embora dotenv seja excelente para desenvolvimento, em produção é comum usar variáveis de ambiente nativas do sistema operacional (Docker, Heroku, AWS Lambda). O dotenv pode ser usado como fallback.
Para validação tipada, considere envalid:
npm install envalid
const { cleanEnv, str, num } = require('envalid');
const env = cleanEnv(process.env, {
PORT: num({ default: 3000 }),
DATABASE_URL: str(),
NODE_ENV: str({ choices: ['development', 'production'] })
});
// env.PORT é number, env.DATABASE_URL é string obrigatória
Resumo das melhores práticas:
1. Sempre use .env para desenvolvimento local
2. Nunca versionar arquivos .env reais
3. Forneça .env.example com valores fictícios
4. Valide variáveis obrigatórias na inicialização
5. Use prefixos específicos (REACT_APP_, VITE_) no frontend
6. Separe configurações por ambiente
7. Prefira variáveis nativas em produção
Com essas práticas, suas aplicações JavaScript + Node.js + React ficarão mais seguras, portáteis e fáceis de configurar em qualquer ambiente.
Referências
- Documentação oficial do dotenv — Repositório oficial com documentação completa, opções de configuração e exemplos de uso
- Variáveis de ambiente no Create React App — Guia oficial sobre como usar variáveis de ambiente com prefixo REACT_APP_
- Variáveis de ambiente no Vite — Documentação oficial do Vite sobre variáveis de ambiente e modos de build
- Documentação do envalid — Biblioteca para validação e tipagem de variáveis de ambiente em Node.js
- Boas práticas de segurança com variáveis de ambiente — Artigo do Twelve-Factor App sobre configuração externa e boas práticas para aplicações modernas
- Node.js process.env documentation — Documentação oficial do Node.js sobre o objeto process.env
- Tutorial: Configurando variáveis de ambiente em projetos Node.js + React — Guia prático do freeCodeCamp sobre uso de variáveis de ambiente em full-stack JavaScript