Feature flags: LaunchDarkly, Flagsmith, Cloudflare Flagship, rollout progressivo
4 min de leitura
Voce fez deploy, mas o PM quer testar a nova feature com 5% dos users antes. Sem feature flag, voce faz 2 deploys (rollout, depois full). Com feature flag, 1 deploy e a flag controla. Esse no cobre feature flags: o pattern de separar deploy de release, com rollout progressivo (10% → 50% → 100%), kill switch instantaneo, e A/B testing com LaunchDarkly, Flagsmith, ou Cloudflare Flagship.
Feature flags mudam a cultura de deploy: em vez de "deploy = release" (vinculado), voce tem "deploy = release controlado" (desvinculado). Beneficios: (1) rollout gradual (10% dos users ve nova UI, 90% ve antiga), (2) kill switch (desliga em 30s sem deploy), (3) A/B test (50% A, 50% B, mede qual converte mais), (4) user targeting (10% dos users em SA-SP ve, Brasil ainda nao).
Voce sai de "deploy arriscado, sem volta" pra "deploy seguro, controle total".
O essencial 🟢
Feature flag em 30 segundos.
import { useFlags } from "launchdarkly-react-client-sdk";
function CheckoutButton() {
const { newCheckout } = useFlags();
if (newCheckout) {
return <NewCheckoutButton />; // 10% dos users
}
return <OldCheckoutButton />; // 90% dos users
}
A flag newCheckout e' configurada
no LaunchDarkly dashboard: 10% dos
users, ou usuarios com email ENDS WITH @beta.com, ou pais = "BR". Codigo
nao muda - flag controla o que
cada user ve.
4 tipos de feature flags.
- Release flag (rollout): liga feature pra % dos users. Mais comum. Apos validar em prod, sobe pra 100%.
- Experiment flag (A/B test): 50% A, 50% B. Mede metrica (conversion, engagement) e escolhe vencedor.
- Operational flag (kill switch): liga/desliga componente critico. Default ON, kill instantaneo se problema.
- Permission flag: "users pro ve X, users free nao ve". User targeting por plano, role, atributo.
Rollout progressivo.
Deploy 1.5.0 com feature flag newCheckout
↓
Dia 1: flag off, 0% ve
Dia 1: liga 1% (canary - early adopters)
Dia 2: sobe pra 10% se metricas ok
Dia 3: 50%
Dia 5: 100% (release completo)
Se metricas ruins (LCP subiu, error rate subiu, conversion caiu): kill flag em 30s, volta pra 100% no antigo. Sem rollback de deploy.
Kill switch - o "por que" feature flags sao obrigatorios. Em prod, bug critico detectado (payment gateway fora, checkout quebrado). Sem kill switch: revert git, build, deploy (15-30min). Com kill switch: toggle flag no dashboard (30s).
function PaymentProcessor() {
const { paymentV2 } = useFlags();
if (paymentV2) {
return <NewPaymentProcessor />; // problematico
}
return <OldPaymentProcessor />; // safe, default
}
Toggle off no LaunchDarkly =
paymentV2 retorna false pra todos
= app volta pro payment antigo em 30s.
LaunchDarkly - o SaaS mais usado.
pnpm add launchdarkly-react-client-sdk
import { withLDProvider, useFlags } from "launchdarkly-react-client-sdk";
function App() {
return (
<LDProvider clientSideID="your-client-id">
<Routes />
</LDProvider>
);
}
function Feature() {
const { newCheckout } = useFlags();
return newCheckout ? <New /> : <Old />;
}
LaunchDarkly pricing: free tier = ate 10 users, pago a partir de $8.33/seat/mes. Self-hosted nao disponivel (SaaS so').
Flagsmith - open source.
pnpm add flagsmith
import flagsmith from "flagsmith";
flagsmith.init({
environmentID: "your-env-id",
});
const flags = await flagsmith.getFlags();
const isEnabled = flags.isFeatureEnabled("new-checkout");
Flagsmith pricing: free tier generoso (1M requests/mes, self-hosted gratis), pago a partir de $45/mes. Open source (GitHub).
Cloudflare Flagship - edge-native (2024+). Flags executadas no edge (Cloudflare Workers), latencia sub-millisecond. Integrado com Cloudflare ecosystem (KV, Durable Objects).
// Cloudflare Worker
export default {
async fetch(request) {
const flag = await FLAGSHIPS.get("new-checkout");
if (flag.enabled) {
return new Response("New checkout");
}
return new Response("Old checkout");
},
};
Cloudflare Flagship pricing: free tier = 1K requests/dia, pago a partir de $0.50/M requests.
Comparacao LaunchDarkly vs Flagsmith vs Cloudflare Flagship.
| Feature | LaunchDarkly | Flagsmith | Cloudflare Flagship |
|---|---|---|---|
| Open source | nao | sim | nao |
| Self-hosted | nao | sim | nao (edge) |
| Latencia | ~50ms | ~50ms | < 5ms (edge) |
| Free tier | 10 seats | 1M req/mes | 1K req/dia |
| Targeting | avancado | basico | basico |
| A/B testing | sim | nao | nao |
| Audit log | sim | sim (pago) | basico |
| Compliance | SOC2 | SOC2 | SOC2 |
Escolha: LaunchDarkly = enterprise (complexo, com A/B test). Flagsmith = open source / mid-market. Cloudflare Flagship = edge-native, low latency.
User targeting - "10% dos users em SA-SP ve, Brasil ainda nao".
Flag: new-checkout
Target:
- country: BR (10% rollout)
- email: contains "@beta.com" (100%)
- userId: 12345 (100% - internal test)
Default: off
Codigo recebe flag booleano. Dashboard configura quem ve. Codigo nao muda quando targeting muda.
Local flag override - dev override.
// Dev mode: force flag on
flagsmith.identify("dev-user", {
customFlags: { "new-checkout": true },
});
Use pra testar todas as combinacoes de flag sem mexer no dashboard.
Feature flag em React, Vue, Svelte.
| Framework | LaunchDarkly | Flagsmith |
|---|---|---|
| React | useFlags() hook | useFlags() hook |
| Vue | $ldReady mixin | composable |
| Svelte | getContext() | getFlags() store |
| Vanilla | client.variation() | flagsmith.getValue() |
Pattern: default safe. Sempre defina um fallback safe (default OFF ou default ON, dependendo do dominio):
function Checkout() {
// Default OLD (conservador)
const { newCheckout } = useFlags();
if (newCheckout) {
return <NewCheckout />;
}
return <OldCheckout />; // default
}
Se feature flag provider cai (server
fora), newCheckout = false, user ve
checkout antigo. Safe.
Pattern: cleanup de flags. Flags sao tecnicas debt - apos 100% rollout, remova o codigo da flag:
// Antes: 2 codigos
function Checkout() {
const { newCheckout } = useFlags();
if (newCheckout) return <NewCheckout />;
return <OldCheckout />;
}
// Depois (apos 100% rollout, flag removida):
function Checkout() {
return <NewCheckout />; // dead code do antigo removido
}
Cleanup evita "flag spaghetti" - cem flags em codigo que ninguem sabe o que fazem.
Aprofundamento 🟡
Targeting rules complexas. LaunchDarkly suporta:
- User attributes:
country,email,plan,customKey(userId). - Segments: grupo de users (ex:
"beta-testers" = todos com email
@company.com). - Rules: combinacoes (AND/OR).
- Prerequisites: "so' ativar se flag X esta' on".
Example rule: 10% rollout, exceto enterprise.
IF user.plan != "enterprise"
AND random(0, 100) < 10
THEN flag = true
ELSE flag = false
A/B testing com feature flags. Use flags como experimentos com metricas:
function PricingPage() {
const { priceVariant } = useFlags();
// priceVariant: "control" | "A" | "B"
// Track no analytics
useEffect(() => {
analytics.track("page_view", { variant: priceVariant });
}, [priceVariant]);
if (priceVariant === "A") return <PriceA />;
if (priceVariant === "B") return <PriceB />;
return <PriceControl />;
}
LaunchDarkly Experimentation calcula significancia estatistica e mostra qual variante venceu. Use pra testes de pricing, copy, layout - mas nao pra mudancas de UI/feature (complexo demais, A/B test tradicional via Optimizely/VWO e' melhor).
Feature flag em SSR (Next.js). No SSR, a flag e' avaliada server-side no primeiro request:
// pages/checkout.tsx (Next.js Pages Router)
import { getLDServerContext } from "launchdarkly-react-client-sdk";
export async function getServerSideProps(context) {
const ldContext = await getLDServerContext({
clientSideID: "your-client-id",
context: { kind: "user", key: context.req.cookies.userId },
});
return {
props: { newCheckout: ldContext.variation("new-checkout", false) },
};
}
Evita flicker (user ve "old" no SSR, "new" no client hydration). Use sempre SSR com feature flags.
Feature flag e compliance. LGPD considera feature flags que fazem targeting por user attributes (email, pais) como "tratamento de dados pessoais". Consentimento pode ser necessario se o targeting individualiza.
OpenFeature - vendor-neutral flags. OpenFeature (CNCF) e' o "OpenTelemetry das feature flags" - 1 API, N providers (LaunchDarkly, Flagsmith, Cloudflare Flagship, Unleash). Vendor-neutrality.
import { OpenFeature } from "@openfeature/js-sdk";
const client = OpenFeature.getClient();
const isEnabled = client.getBooleanValue("new-checkout", false);
Em 2026, OpenFeature ainda em rollout. Considere se quiser vendor- neutrality.
Feature flag local - simples, sem SaaS. Pra apps sem LaunchDarkly orçamento, use .env ou config JSON:
// config/features.json
{
"newCheckout": {
"enabled": true,
"rollout": 0.1
}
}
import features from "./config/features.json";
const userHash = hashUserId(userId);
if (features.newCheckout.enabled && userHash < features.newCheckout.rollout) {
return <NewCheckout />;
}
Limitado: sem dashboard, sem targeting complexo, sem audit log. OK pra apps pequenos, insuficiente pra enterprise.
Pra quem quer ir mais alem 🔴
LaunchDarkly Relay Proxy. Self-hosted proxy entre client e LaunchDarkly server. Reduz latencia (cache local), aumenta seguranca (cliente nao chama SaaS direto), funciona offline (cache). Use em apps com muitos clients mobile.
Feature flag em mobile (RN, native). LaunchDarkly SDK funciona em React Native, iOS (Swift), Android (Kotlin). Cuidado com offline - mobile perde rede. Cache last value + default fallback.
Trunk-based development + feature flags. Trunk-based = todos committam em main, sem branches longos. Feature flags sao obrigatorias - cada feature em branch proprio nao pode mergear ate "pronto". Com flags, merge cedo, release gradual. Cultura que Flickr, Google, Facebook usam desde 2010.
Anti-patterns de feature flags.
- Long-lived flags (> 6 meses) - technical debt, "flag spaghetti".
- Nested flags (flag dentro de flag) - impossivel testar todas combinacoes.
- Flag explosion - 100+ flags em codigo, sem owner claro. Cada flag deve ter owner (time que criou) e data de remocao.
- Magic flag values ("string 'A' = tratamento X, string 'B' = tratamento Y") - use boolean ou enum explicitamente.
**Feature flag e Continuous Delivery. ** Flags complementam CD, nao substituem. CD = deploy automatico em cada merge. Feature flag = controle de release independente do deploy. Juntos = deploy rapido
- release seguro.
Leitura recomendada:
- LaunchDarkly - Docs - setup, targeting, A/B testing, code references.
- Flagsmith - Open Source - self-hosted, open source, API completa.
- Cloudflare - Flagship - edge-native, baixa latencia, integracao com Workers.
Dica: o erro mais comum em feature flags e' "vamos usar pra tudo". Resultado: codigo com 30 flags aninhadas, impossivel testar. Use feature flags pra 4 cenarios: (1) rollout progressivo de feature grande, (2) kill switch de componente critico, (3) A/B test de copy/pricing, (4) permission/plan-based. Nao use pra: configuracao de UI ("dark mode on/off" nao e' feature flag, e' config), A/B test de copy pequeno (use SaaS proprio), ou refactor interno (git branch resolve). Cada flag deve ter owner e data de remocao - 6 meses max.
No proximo no (ultimo teorico), vamos PII e privacidade: como scrubbing, consentimento, e data minimization afetam Sentry, OTel, e feature flags em contexto de LGPD/GDPR. Cobre o "lado juridico" de observabilidade.
// Quiz
Por que feature flags sao obrigatorios em times que praticam Continuous Deployment / trunk-based development?