O problema da configuração
Um mesmo servidor é executado em vários ambientes: seu notebook (development),
um servidor de testes (staging) e produção (production). Cada um precisa
de valores diferentes: a porta, a URL do banco de dados, as chaves de APIs
externas... Se você hardcoda esses valores no código, mistura o que muda
(a config) com o que não muda (o programa), e acaba com um if (ambiente === "prod")
espalhado por toda parte.
A metodologia 12-factor
The Twelve-Factor App é um conjunto de boas práticas para construir serviços. Seu fator III (Config) diz:
Guarde a configuração no ambiente, não no código.
Em concreto:
- A config vive em variáveis de ambiente (
process.env), não no repositório. - O mesmo build (o mesmo código e artefato) é implantado em todos os ambientes; a única coisa que muda é o ambiente que o cerca.
- Um bom teste: você conseguiria tornar open source o repo agora mesmo sem vazar nenhuma credencial? Se a resposta for não, você tem segredos no código.
// No Node, as variáveis de ambiente chegam em process.env (sempre strings).
const PORT = process.env.PORT; // "3000"
const NODE_ENV = process.env.NODE_ENV; // "production"
Centralizar e definir valores padrão
Em vez de ler process.env por todo o código, centralize a leitura em um
único módulo de config que valida e aplica valores padrão. Assim o resto
da aplicação recebe um objeto limpo e tipado:
function carregarConfig(env) {
return {
port: Number(env.PORT) || 3000,
ambiente: env.NODE_ENV || "development",
};
}
const config = carregarConfig(process.env);
Nestes exercícios injetamos o ambiente como um objeto
env(em vez de lerprocess.envdiretamente). Isso torna a config testável: você pode testar a mesma função com{}, com{ PORT: "8080" }, etc.
Separar config por ambiente
O valor de NODE_ENV decide o comportamento: em development você quer logs
detalhados e mensagens de erro completas; em production, logs compactos e erros
genéricos (para não vazar detalhes internos). O código é o mesmo; só
mudam os valores que ele recebe.
Gerenciamento de segredos
As senhas, tokens e chaves são config especialmente sensível:
- Nunca são commitados. Em local usa-se um arquivo
.env(ignorado pelo git, carregado com uma biblioteca comodotenv); em produção são injetados pela plataforma (Docker, Kubernetes Secrets, AWS Secrets Manager, Vault...). - O repo inclui um
.env.examplecom as chaves sem valores, como documentação. - A aplicação deve falhar ao iniciar (fail fast) se faltar um segredo obrigatório, em vez de quebrar no meio de uma requisição.
Exemplos
Config centralizada com defaults e validação de segredos
function carregarConfig(env) {
if (env.NODE_ENV === "production" && !env.DATABASE_URL) {
throw new Error("Falta DATABASE_URL em produção");
}
return {
port: Number(env.PORT) || 3000,
ambiente: env.NODE_ENV || "development",
dbUrl: env.DATABASE_URL || "memoria://local",
};
}
console.log(carregarConfig({ PORT: "8080" }));
console.log(carregarConfig({}));