Usar Feature Flags no Node.js permite ativar ou desativar funcionalidades sem publicar uma nova versão. Uma flag pode liberar um recurso apenas para a equipe, para uma porcentagem dos usuários, para uma organização específica ou para todos, oferecendo controle durante testes, migrações e incidentes.
Flags reduzem o risco de deploy ao separar entrega de código da liberação do comportamento. Porém, também criam caminhos condicionais, dívida técnica e dependência de configuração. Uma flag mal avaliada pode expor recursos, produzir experiências inconsistentes ou ficar esquecida por anos.
Neste guia, você aprenderá tipos de flags, avaliação local e remota, defaults seguros, targeting, rollout percentual, cache, observabilidade, testes, remoção e práticas de segurança.
O que são Feature Flags?
Feature flag é uma decisão em tempo de execução que seleciona um comportamento. A documentação oficial do OpenFeature apresenta uma API padronizada e independente de fornecedor. A referência de Martin Fowler sobre feature toggles explica categorias e ciclo de vida.
Para configuração simples no Kubernetes, consulte ConfigMaps e Secrets no Node.js. Para deploy gradual, veja Probes Kubernetes em Node.js.
Tipos de flags
- Release: esconde código incompleto até estar pronto.
- Experiment: divide usuários para comparar resultados.
- Operational: desliga uma integração ou tarefa pesada.
- Permission: habilita recurso contratado ou autorizado.
- Migration: alterna entre implementações antiga e nova.
Cada categoria possui duração e controle diferentes.
Flag booleana simples
const enabled = process.env.NEW_CHECKOUT_ENABLED === 'true';
if (enabled) {
return renderNewCheckout();
}
return renderLegacyCheckout();Esse modelo exige restart quando o valor vem de variável de ambiente.
Defaults seguros
function parseBoolean(value, fallback = false) {
if (value === 'true') return true;
if (value === 'false') return false;
return fallback;
}Uma flag operacional de risco deve falhar fechada. Uma flag de observabilidade talvez possa usar true como default. Documente a escolha.
Não confunda flag com variável de ambiente
Variáveis atendem configuração estática. Uma plataforma de flags oferece atualização dinâmica, targeting, auditoria, histórico e rollout gradual.
Objeto de configuração local
const flags = Object.freeze({
newCheckout: false,
recommendationEngine: true,
maxBatchVersion: 2
});Centralize acesso em uma função, em vez de espalhar leitura de configuração pelo código.
Cliente de flags
async function isEnabled(name, context, fallback = false) {
try {
return await provider.getBooleanValue(
name,
fallback,
context
);
} catch (error) {
logger.warn({ err: error, flag: name }, 'Falha ao avaliar flag');
return fallback;
}
}A indisponibilidade do provedor não deve bloquear indefinidamente a requisição.
Contexto de avaliação
const context = {
targetingKey: String(user.id),
organizationId: String(user.organizationId),
country: user.country,
plan: user.plan
};Envie apenas atributos necessários. Não inclua e-mail, documento ou token sem justificativa.
Targeting por usuário
Uma allowlist ajuda a liberar para equipe interna:
if (internalUserIds.has(user.id)) {
return true;
}Não use essa lógica como autorização. O usuário ainda precisa de permissões para executar a operação.
Targeting por organização
Recursos B2B podem ser liberados por tenant. Use identificador estável e confirme isolamento de dados independentemente da flag.
Rollout percentual
Uma divisão consistente usa hash:
function bucket(key, flagName) {
const hash = createHash('sha256')
.update(`${flagName}:${key}`)
.digest();
return hash.readUInt32BE(0) % 10000;
}
function included(key, flagName, percentage) {
return bucket(key, flagName) < percentage * 100;
}O mesmo usuário permanece no grupo enquanto chave e algoritmo não mudarem.
Não use Math.random por requisição
O usuário alternaria entre experiências a cada chamada, corrompendo métricas e estado.
Unidade de randomização
Escolha usuário, organização, dispositivo ou sessão conforme o experimento. Em B2B, dividir membros da mesma organização pode gerar inconsistência.
Variantes
const variant = await provider.getStringValue(
'checkout-layout',
'control',
context
);
switch (variant) {
case 'compact':
return compactCheckout();
case 'guided':
return guidedCheckout();
default:
return controlCheckout();
}Valide variantes desconhecidas e use fallback.
Flags numéricas
Uma flag pode controlar limite, timeout ou quantidade:
const batchSize = await provider.getNumberValue(
'worker-batch-size',
20,
context
);Aplique faixa mínima e máxima antes de usar.
Configuração JSON
Objetos complexos podem ser retornados, mas aumentam risco de schema incompatível. Versione e valide:
const config = featureConfigSchema.parse(rawConfig);Cache local
SDKs mantêm cache ou stream de atualizações. Defina comportamento quando os dados expiram:
- usar último valor conhecido;
- usar fallback;
- bloquear operação crítica;
- marcar serviço como degradado.
Timeout de avaliação
Uma requisição não deve esperar segundos por um serviço de flags:
const signal = AbortSignal.timeout(100);Prefira avaliação local com dados sincronizados quando baixa latência é necessária.
Inicialização do SDK
A aplicação pode esperar o cliente ficar pronto antes de marcar readiness. Para flags não críticas, iniciar com defaults pode ser aceitável.
Readiness
Se uma flag decide acesso a pagamento ou migração de dados, o provedor pode ser dependência crítica. Caso contrário, fallback deve permitir o serviço funcionar.
Kill switch
Uma flag operacional pode desligar uma integração problemática:
if (!await isEnabled('payment-provider-enabled', context, false)) {
throw new ServiceUnavailableError();
}O caminho de desligamento precisa ser testado antes do incidente.
Degradação controlada
Em vez de falhar, desative recomendações, relatórios pesados ou enriquecimento opcional e mantenha a função principal.
Migração de implementação
const useNewRepository = await isEnabled(
'new-orders-repository',
context,
false
);
return useNewRepository
? newRepository.find(id)
: legacyRepository.find(id);Compare resultados em shadow mode antes de enviar o novo resultado ao usuário.
Shadow traffic
A implementação nova executa sem controlar a resposta. Compare duração e resultado, com limites para não duplicar efeitos.
Escrita dupla
Durante migração, escrever em dois destinos é arriscado. Use idempotência, outbox e reconciliação. Consulte Idempotência em APIs Node.js.
Experimentos
Defina hipótese, métrica primária, guardrails e duração antes de iniciar. Não altere percentuais constantemente sem considerar análise estatística.
Exposição
Registre quando o usuário realmente foi exposto à variante, não apenas quando a flag foi avaliada.
Feature flag não é autorização
Esconder uma tela não protege o endpoint. Valide função, plano e permissão no backend.
Dados sensíveis
Não coloque segredos em payload de flags entregue ao cliente. Use Secrets para credenciais.
Auditoria
Registre:
- quem alterou;
- valor anterior e novo;
- horário;
- ambiente;
- motivo;
- ticket ou incidente;
- data de expiração.
Ownership
Cada flag deve ter responsável. Sem owner, ninguém sabe quando remover.
Data de expiração
Flags de release devem expirar pouco depois da liberação total. Crie alerta ou regra de lint para flags antigas.
Nomes
Use nomes claros:
checkout.new-address-formEvite nomes negativos duplos como disable-old-checkout-false.
Ambientes
Desenvolvimento, homologação e produção devem ter configurações separadas. Uma alteração de teste não deve ativar produção.
Flags no frontend e backend
Avaliar no frontend melhora interface, mas decisões de segurança precisam ser repetidas no servidor. Variantes devem permanecer coerentes entre camadas.
Propagando variante
Quando dois serviços precisam da mesma decisão, envie a variante como contexto assinado ou garanta que ambos usem a mesma chave e configuração.
Consistência
Atualizações podem chegar em momentos diferentes às instâncias. Para mudanças incompatíveis, mantenha código capaz de operar com os dois valores durante a propagação.
Deploy e flags
Implante primeiro código compatível com flag desligada. Depois ative gradualmente. Para remover, torne o novo comportamento padrão, retire o antigo e só então exclua a flag.
Blue-green e canary
Flags controlam comportamento dentro da aplicação; estratégias de deploy controlam tráfego entre versões. Elas podem ser combinadas, mas possuem responsabilidades diferentes.
Observabilidade
Inclua a variante em logs e traces com cardinalidade controlada:
logger.info({
flag: 'checkout-layout',
variant
}, 'Checkout renderizado');Consulte Logs com Pino no Node.js.
Métricas
Monitore taxa de erro, latência e resultado de negócio por variante. Consulte Métricas Prometheus no Node.js. Não use userId como label.
Sentry
Adicione flag e variante como tags de baixa cardinalidade para identificar regressões. Consulte Sentry no Node.js.
Testes unitários
test('usa checkout novo quando flag ativa', async () => {
const flags = fakeFlags({
'new-checkout': true
});
const result = await renderCheckout({ flags });
assert.equal(result.version, 'new');
});Teste ambos os caminhos
Cubra flag ligada, desligada, variante inválida, timeout e fallback.
Testes de integração
Use provider em memória para resultados determinísticos. Não dependa do serviço remoto no CI.
Testes de remoção
Quando a flag chega a 100%, remova o caminho antigo e os testes correspondentes. O novo comportamento deve continuar coberto.
Erros comuns
- Math.random por chamada: usuário muda de variante.
- Flag como autorização: endpoint fica exposto.
- Sem fallback: provedor derruba a aplicação.
- Dados pessoais no contexto: privacidade é afetada.
- Flags eternas: complexidade cresce.
- Ativar antes do código: instâncias antigas falham.
- Sem métricas: regressão não é percebida.
Boas práticas
- Centralize avaliação.
- Use defaults seguros.
- Defina targeting estável.
- Use hash para rollout.
- Valide variantes.
- Limite timeout.
- Audite mudanças.
- Defina owner e expiração.
- Monitore por variante.
- Remova flags antigas.
Conclusão
Usar Feature Flags no Node.js separa deploy de lançamento e permite controlar risco com targeting, rollout percentual e kill switches. O código pode chegar desligado, ser ativado para pequenos grupos e voltar ao comportamento anterior sem novo build.
O benefício depende de governança. Defaults, auditoria, métricas, ownership e data de remoção evitam que flags se tornem dívida permanente. Quando segurança continua no backend e o provedor possui fallback, flags oferecem controle operacional sem comprometer a estabilidade.



