<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Flaggy</title>
    <description>The latest articles on Forem by Flaggy (@flaggy).</description>
    <link>https://forem.com/flaggy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3937786%2F3bf332f4-7a6a-428e-855a-62e034a2dabf.png</url>
      <title>Forem: Flaggy</title>
      <link>https://forem.com/flaggy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/flaggy"/>
    <language>en</language>
    <item>
      <title>How to use feature flags in JavaScript and TypeScript</title>
      <dc:creator>Flaggy</dc:creator>
      <pubDate>Wed, 20 May 2026 02:17:00 +0000</pubDate>
      <link>https://forem.com/flaggy/how-to-use-feature-flags-in-javascript-and-typescript-9k7</link>
      <guid>https://forem.com/flaggy/how-to-use-feature-flags-in-javascript-and-typescript-9k7</guid>
      <description>&lt;p&gt;A practical guide to implementing &lt;a href="https://flaggy.io/features/flags/" rel="noopener noreferrer"&gt;feature flags&lt;/a&gt; in JS/TS: what they are, when to use them, and how to avoid the traps that make them painful to manage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flaggy.io/features/flags" rel="noopener noreferrer"&gt;Feature flags&lt;/a&gt; are a conditional: if (flagEnabled) { show new thing } else { show old thing }. That’s the entire concept. The value comes from where the condition is evaluated and who controls it — not the developer at deploy time, but a dashboard at runtime.&lt;/p&gt;

&lt;p&gt;This guide covers the core patterns, when each one applies, and what separates a well-managed flag from one that quietly rots in your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The basic pattern
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://flaggy.io/features/flags/" rel="noopener noreferrer"&gt;feature flag&lt;/a&gt; SDK gives you a function. You call it with a flag key, optionally a user context, and it returns a boolean (or a variant, for multivariate flags).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flaggy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@flaggy.io/sdk-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flaggy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FLAGGY_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;release-checkout-flow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NewCheckout&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LegacyCheckout&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK downloads your ruleset on initialization and evaluates locally. No network call happens at the point of evaluation — it’s a dictionary lookup against rules in memory. This is why MAU-based pricing from some vendors doesn’t make technical sense: the vendor’s infrastructure isn’t involved when a flag evaluates.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use a feature flag
&lt;/h2&gt;

&lt;p&gt;Release control is the most common case. You merge a half-finished feature to main behind a flag, deploy continuously, and flip the flag when it’s ready. No long-lived feature branches, no merge conflicts.&lt;/p&gt;

&lt;p&gt;Percentage rollouts let you ship to 5% of users, watch your error rate, and expand if it looks clean. This is a canary deployment without the infrastructure complexity of actually routing traffic.&lt;/p&gt;

&lt;p&gt;User targeting lets you ship to internal users, beta testers, or a specific customer &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt; first. You define a &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt; in the dashboard — “users where plan = enterprise” — and enable the flag for that &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Kill switches are flags you never intend to remove. A circuit breaker on a third-party integration, a way to disable a feature if it’s causing support volume. Having this in a dashboard is faster than a deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The initialization pattern
&lt;/h2&gt;

&lt;p&gt;Initialize the SDK once at app startup and share the client. Don’t initialize per-request or per-component — it defeats the local evaluation model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// flaggy.ts — initialize once, export everywhere&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flaggy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@flaggy.io/sdk-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flaggy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FLAGGY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// any component or module&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./flaggy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showFeature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Targeting rules
&lt;/h2&gt;

&lt;p&gt;Most SDKs let you pass a context object — any key/value pairs you want to use for targeting. The dashboard lets you define rules against those attributes without a code change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common context attributes:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;experiment-dark-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// target by billing tier&lt;/span&gt;
  &lt;span class="na"&gt;accountAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;daysSinceSignup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You define the rule once in the dashboard: “users where plan = team AND accountAge &amp;gt; 30”. No deploy required to change targeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cleanup problem
&lt;/h2&gt;

&lt;p&gt;The real cost of &lt;a href="https://flaggy.io/features/flags/" rel="noopener noreferrer"&gt;feature flags&lt;/a&gt; isn’t evaluating them — it’s the ones you forget to remove. A codebase with 200 permanent flags is harder to reason about than one with 20.&lt;/p&gt;

&lt;p&gt;A few habits that help:&lt;/p&gt;

&lt;p&gt;Add a ticket at flag creation. When you create a flag, immediately create a ticket to remove it after the rollout is done. The flag has a lifespan of “rollout + one release cycle.”&lt;/p&gt;

&lt;p&gt;Name flags by lifecycle prefix. Use a prefix that encodes intent: release-new-dashboard, experiment-checkout-button, kill-switch-payment-provider, ops-cache-ttl. It makes lifespan visible at a glance — you can immediately separate flags that need cleanup from ones that are permanent.&lt;/p&gt;

&lt;p&gt;Review old flags quarterly. Pull a list of flags that haven’t changed in 90 days. Most of them are either fully rolled out (safe to remove) or forgotten experiments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-side vs client-side evaluation
&lt;/h2&gt;

&lt;p&gt;Some teams evaluate flags server-side to avoid any flag state being visible in the client bundle. The tradeoff:&lt;/p&gt;

&lt;p&gt;Client-side: zero latency at evaluation, no server dependency, flag rules are technically visible in the bundle (usually fine for most use cases)&lt;br&gt;
Server-side: rules stay private, adds one lookup per request (fast if in-memory, latency concern if remote)&lt;br&gt;
For most product flags — rollouts, A/B tests, kill switches — client-side evaluation is fine. For flags that gate access control or pricing, server-side is worth the overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to look for in a flag platform
&lt;/h2&gt;

&lt;p&gt;You need: a dashboard to manage flags without a code change, targeting rules, &lt;a href="https://flaggy.io/features/audit-log/" rel="noopener noreferrer"&gt;audit history&lt;/a&gt; (who changed what and when), and an SDK that evaluates locally.&lt;/p&gt;

&lt;p&gt;What you don’t need to pay for: MAU metering. Modern SDKs evaluate client-side. The vendor’s servers aren’t involved in evaluations — if you’re paying per-MAU, you’re paying for a proxy metric that doesn’t reflect actual vendor cost.&lt;/p&gt;

&lt;p&gt;Flaggy’s Team plan is $99/month flat — unlimited seats, no MAU fees, full flag analytics and &lt;a href="https://flaggy.io/features/audit-log/" rel="noopener noreferrer"&gt;audit log&lt;/a&gt; included.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>frontend</category>
      <category>sass</category>
    </item>
    <item>
      <title>Feature flag best practices for engineering teams</title>
      <dc:creator>Flaggy</dc:creator>
      <pubDate>Tue, 19 May 2026 04:40:00 +0000</pubDate>
      <link>https://forem.com/flaggy/feature-flag-best-practices-for-engineering-teams-okf</link>
      <guid>https://forem.com/flaggy/feature-flag-best-practices-for-engineering-teams-okf</guid>
      <description>&lt;p&gt;The patterns that make &lt;a href="https://flaggy.io/features/flags/" rel="noopener noreferrer"&gt;feature flags&lt;/a&gt; useful long-term, and the habits that keep them from becoming a maintenance burden. Drawn from common failure modes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flaggy.io/features/flags/" rel="noopener noreferrer"&gt;Feature flags&lt;/a&gt; are simple in concept. The failure modes are also simple, and predictable. Most teams hit the same three problems: flags that never get cleaned up, targeting rules nobody understands, and flag state that’s invisible to the people who need it.&lt;/p&gt;

&lt;p&gt;Here are the practices that prevent each of those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Name flags by intent, not implementation
&lt;/h2&gt;

&lt;p&gt;A flag named “New dashboard v2” tells you what it wraps but not why it exists or when it ends. A flag named “Release dashboard redesign” communicates both that it’s temporary and what it controls.&lt;/p&gt;

&lt;p&gt;A useful naming convention uses a prefix word to encode the flag’s lifecycle. In Flaggy, names are entered as plain text and the key is generated automatically — “Release dashboard redesign” becomes the key release-dashboard-redesign in your code.&lt;/p&gt;

&lt;p&gt;Useful prefixes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release&lt;/strong&gt; — enables a new feature during a gradual release. Intended to be removed once fully shipped. e.g. “Release dashboard redesign”&lt;br&gt;
&lt;strong&gt;Experiment&lt;/strong&gt; — an A/B test. Has a defined end date. e.g. “Experiment checkout button color”&lt;br&gt;
&lt;strong&gt;Kill switch&lt;/strong&gt; — a permanent circuit breaker. Not expected to be removed. e.g. “Kill switch payments integration”&lt;br&gt;
&lt;strong&gt;Ops&lt;/strong&gt; — a configuration flag for operational tuning. May be permanent. e.g. “Ops cache TTL override”&lt;/p&gt;

&lt;p&gt;The prefix communicates lifespan at a glance. When you’re reviewing a list of 50 flags, you can immediately separate the ones that should be cleaned up from the ones that are load-bearing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create the cleanup ticket at flag creation
&lt;/h2&gt;

&lt;p&gt;The most reliable way to remove a flag is to plan for it before you merge. When you create a flag in the dashboard, immediately create a ticket in your issue tracker: “Remove flag &lt;code&gt;rollout-feature-name&lt;/code&gt; after full rollout.”&lt;/p&gt;

&lt;p&gt;Without this step, the flag gets created with full intention to clean it up, but the rollout ends, the team moves on, and the ticket never gets written. Flags accumulate. After a year you have 150 flags and nobody knows which ones are active.&lt;/p&gt;

&lt;p&gt;The sequence is: create flag → create cleanup ticket → merge code → run rollout → remove flag → close ticket.&lt;/p&gt;
&lt;h2&gt;
  
  
  Set flag context consistently
&lt;/h2&gt;

&lt;p&gt;The user context you pass to the SDK determines what targeting rules you can write. If different parts of the app pass different context attributes, you end up with targeting rules that silently don’t apply everywhere.&lt;/p&gt;

&lt;p&gt;Define a canonical context object and build it in one place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildFlagContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;FlagContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptionPlan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;teamId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teamId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;accountAgeDays&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;differenceInDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this everywhere. When you add a new attribute, add it here and it becomes available for targeting across the entire app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep flag logic at the boundary, not deep in components
&lt;/h2&gt;

&lt;p&gt;Flag checks embedded deep in component trees or utility functions are hard to find and easy to forget. Prefer pushing flag evaluation to the boundary of a feature — the entry point that decides which version to render.&lt;/p&gt;

&lt;p&gt;Harder to clean up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// buried in a utility function&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-pricing-display&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;newFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;legacyFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easier to clean up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// at the component boundary&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PricingSection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useNewDisplay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-pricing-display&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useNewDisplay&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NewPricingDisplay&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LegacyPricingDisplay&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second version makes the flag visible at a high level. When you remove it, you delete the condition and the LegacyPricingDisplay import — the diff is obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use segments for reusable targeting logic
&lt;/h2&gt;

&lt;p&gt;If you find yourself writing the same targeting rule on multiple flags — “users where plan = team AND accountAge &amp;gt; 30 days” — define it as a &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt; once and target the &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;p&gt;Rules are consistent. If your definition of “beta users” changes, you update it in one place.&lt;br&gt;
Auditing is easier. You can see which flags target a &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt;.&lt;br&gt;
Onboarding new team members is simpler — they see named &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segments&lt;/a&gt;, not repeated rule logic.&lt;br&gt;
&lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;Segments&lt;/a&gt; with clear names also make flag state legible to non-engineers. “This flag is enabled for the Beta Users &lt;a href="https://flaggy.io/features/segments/" rel="noopener noreferrer"&gt;segment&lt;/a&gt;” is understandable to a PM in a way that a list of attribute conditions isn’t.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make flag state visible to the right people
&lt;/h2&gt;

&lt;p&gt;The support engineer who gets a ticket about a broken feature needs to check flag state. The PM managing a rollout wants to see current coverage. The on-call engineer debugging an incident needs to know which flags are currently active.&lt;/p&gt;

&lt;p&gt;This is the hidden argument for unlimited seats: restricting dashboard access to the engineers who created the flags means everyone else is guessing. “Is this behind a flag?” becomes a Slack thread instead of a 30-second dashboard check.&lt;/p&gt;

&lt;p&gt;Every person who touches your product in some capacity — PM, design, support, on-call — should be able to read flag state without asking an engineer.&lt;/p&gt;
&lt;h2&gt;
  
  
  Test the off state
&lt;/h2&gt;

&lt;p&gt;When you add a flag, write a test for both branches — not just the new behavior you’re building.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout flow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shows new flow when flag is enabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;mockFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-checkout-flow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shows legacy flow when flag is disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;mockFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-checkout-flow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The off state breaks silently. The old code path doesn’t get touched during development, gets skipped in manual testing, and only fails in production when a flag gets rolled back. Test both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define a rollout pace
&lt;/h2&gt;

&lt;p&gt;“We’ll do a gradual rollout” is not a plan. Before you flip the flag, decide:&lt;/p&gt;

&lt;p&gt;What percentage you’ll start at (common: 1–5%)&lt;br&gt;
What metric signals it’s safe to expand (error rate, p99 latency, specific event count)&lt;br&gt;
How long you’ll hold at each stage before expanding&lt;br&gt;
What triggers a rollback&lt;br&gt;
Write this down somewhere. It doesn’t need to be formal — a comment in the cleanup ticket is enough. The goal is that whoever is on-call at 2am knows the answer to “is this flag supposed to be at 10%?” without having to find the person who created it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit logs are not optional
&lt;/h2&gt;

&lt;p&gt;You will have a production incident caused by a flag change. Someone will toggle something at the wrong time, or a targeting rule will match more users than expected, or the SDK will behave differently on an edge case.&lt;/p&gt;

&lt;p&gt;When that happens, the first question is: what changed, when, and who changed it? An &lt;a href="https://flaggy.io/features/audit-log/" rel="noopener noreferrer"&gt;audit log&lt;/a&gt; that captures every flag toggle, rule edit, and segment update is how you answer that in minutes instead of hours.&lt;/p&gt;

&lt;p&gt;This is not a nice-to-have — it’s incident response infrastructure. Flaggy includes &lt;a href="https://flaggy.io/features/audit-log/" rel="noopener noreferrer"&gt;audit logging&lt;/a&gt; on all plans, including the Free tier (7-day retention). The Team plan extends this to 90 days — worth considering if your incident review windows run longer.&lt;/p&gt;

&lt;p&gt;If you're looking for a feature flag tool built around these practices — with automatic key generation from plain-text names, flag lifecycle visibility, and a clean dashboard — check out &lt;a href="https://flaggy.io/" rel="noopener noreferrer"&gt;Flaggy&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>Feature flag rollouts: canary-style risk reduction without the infrastructure</title>
      <dc:creator>Flaggy</dc:creator>
      <pubDate>Mon, 18 May 2026 11:22:03 +0000</pubDate>
      <link>https://forem.com/flaggy/canary-deployments-with-feature-flags-reduce-release-risk-without-the-infrastructure-26nm</link>
      <guid>https://forem.com/flaggy/canary-deployments-with-feature-flags-reduce-release-risk-without-the-infrastructure-26nm</guid>
      <description>&lt;p&gt;Canary deployments and &lt;a href="https://flaggy.io/features/flags" rel="noopener noreferrer"&gt;feature flag&lt;/a&gt; rollouts solve the same problem at different layers. Here's how they actually work, when to use each, and how to combine them.&lt;/p&gt;

&lt;p&gt;A canary deployment releases a new version of your application to a small slice of users before rolling it out fully. If something breaks, you catch it at 5% of traffic instead of 100%.&lt;/p&gt;

&lt;p&gt;Feature flags solve the same problem at a different layer. Understanding the distinction helps you pick the right tool — and combine them when it makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  How traditional canary deployments work
&lt;/h2&gt;

&lt;p&gt;A canary deployment means running two versions of your application simultaneously in production. Version A is your current stable release. Version B is the new version. A routing layer — a load balancer, a service mesh, or your orchestration platform — directs a percentage of traffic to version B while the rest continues to hit version A.&lt;/p&gt;

&lt;p&gt;In Kubernetes, the most common implementation uses two Deployments sharing a single Service selector. The Service routes traffic across all matching pods, so the traffic split is determined by the ratio of replicas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# stable: 9 replicas
# canary: 1 replica
# → roughly 90% / 10% split
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More sophisticated setups use an ingress controller (like NGINX or Traefik) or a service mesh (like Istio or Linkerd) to control the split with explicit weights, independent of replica count. This gives you precise percentages without scaling your fleet.&lt;/p&gt;

&lt;p&gt;The key point: a canary deployment is an infrastructure strategy. Both versions of your code are running in production. The routing layer decides which users hit which version.&lt;/p&gt;

&lt;h2&gt;
  
  
  How feature flag rollouts work
&lt;/h2&gt;

&lt;p&gt;A feature flag rollout is an application-layer strategy. You deploy a single version of your application to all servers. Inside that code, a flag evaluation controls which code path executes for a given user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flaggy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@flaggy.io/sdk-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flaggy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FLAGGY_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useNewAlgorithm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-recommendation-engine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useNewAlgorithm&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;newRecommendationEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;legacyRecommendationEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key field ensures the same user always gets a consistent experience — the percentage is applied by hashing the key, not by random chance per request.&lt;/p&gt;

&lt;p&gt;The key point: a feature flag rollout is a code strategy. One binary is deployed. The flag determines which behavior that binary exhibits for each user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The difference in practice
&lt;/h2&gt;

&lt;p&gt;Both approaches answer the same question: is this change safe at scale before committing fully? But they operate at different layers and have different strengths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Canary deployments&lt;/strong&gt; are managed by infrastructure or DevOps teams. Rollback means shifting traffic back to the stable version and eventually tearing down the canary — it’s a deployment operation. All changes in the new version are rolled back together; you can’t independently revert one feature if it shares a deployment with others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature flag rollouts&lt;/strong&gt; are managed by the team shipping the feature. Rollback means flipping a flag — it takes seconds and requires no deployment. Each feature has its own flag, so you can roll back one independently without touching anything else in the same release.&lt;/p&gt;

&lt;p&gt;Another difference: canary deployments work at the traffic level, not the user level. You can route based on headers, cookies, or geographic region — but you’re routing requests, not targeting specific users. Feature flags can target individual users, user attributes, cohorts, or &lt;a href="https://flaggy.io/features/segments" rel="noopener noreferrer"&gt;segments&lt;/a&gt;. You can enable a feature for your beta group specifically, then expand to a percentage of everyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Percentage rollouts with Flaggy
&lt;/h2&gt;

&lt;p&gt;The basic pattern is a flag with a percentage rollout rule. Start at 5%, verify your metrics look clean, expand in stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring during rollout
&lt;/h3&gt;

&lt;p&gt;Before you expand, you need something to watch:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error rates&lt;/strong&gt;. Instrument both code paths with error tracking. An increase in exceptions for users in the new path is the clearest signal something is wrong.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useNewAlgorithm&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;newRecommendationEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;legacyRecommendationEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;errorTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flagVariant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;useNewAlgorithm&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;legacy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Latency&lt;/strong&gt;. New code paths are often slower. Tag your performance measurements with the flag variant so you can compare p50/p99 between the two groups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business metrics&lt;/strong&gt;. For user-facing features, watch the metrics that matter for the feature itself — conversion rate, click-through rate, session length. These take longer to accumulate signal but catch subtler problems that error rates miss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flag evaluation split&lt;/strong&gt;. &lt;a href="https://flaggy.io" rel="noopener noreferrer"&gt;Flaggy&lt;/a&gt;’s analytics show the true/false breakdown for each flag in real time. If you set a 10% rollout and the split reads 0% or 100%, something is wrong before your error tracker has had time to accumulate signal.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rollout ladder
&lt;/h3&gt;

&lt;p&gt;A sensible default for most features:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby34d0ckyxn3jcea82ph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby34d0ckyxn3jcea82ph.png" alt=" " width="740" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can compress this for low-risk changes or extend it for changes with high blast radius. The goal is giving each stage enough time to accumulate error budget signal, not following the ladder for its own sake.&lt;/p&gt;

&lt;p&gt;Write the ladder down before you start. On-call engineers shouldn’t have to find the person who created the flag to know whether 25% coverage is expected or a bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Staged rollouts: internal team first
&lt;/h2&gt;

&lt;p&gt;Percentage rollouts distribute randomly across your user base. For higher-risk changes, you want more control over who gets the new behavior first.&lt;/p&gt;

&lt;p&gt;The pattern: enable the flag for internal users or beta testers before opening any percentage rollout. If something breaks, your team finds it — not your customers.&lt;/p&gt;

&lt;p&gt;In Flaggy:&lt;/p&gt;

&lt;p&gt;Create a segment: "users where email ends with @yourcompany.com"&lt;br&gt;
Enable the flag for that segment — your team gets the new behavior&lt;br&gt;
Run it internally for a few days, file bugs, fix them&lt;br&gt;
Then start the percentage rollout for the broader user base&lt;br&gt;
You can stack these rules: the flag is on for the internal segment and for 5% of everyone else. The two targeting rules work independently.&lt;/p&gt;

&lt;p&gt;The Free plan includes 2 segments — enough for an internal team and a beta group. The Team plan has unlimited segments.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use infrastructure canary deployments instead
&lt;/h2&gt;

&lt;p&gt;Feature flag rollouts handle application-level changes well. There are cases where you need infrastructure-level canaries:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database schema migrations&lt;/strong&gt;. Running two versions of your app simultaneously lets you verify the new schema is compatible before fully migrating. A flag can’t help if the migration breaks the old code path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency and runtime upgrades&lt;/strong&gt;. Upgrading a major version of a core library, or moving to a new runtime version, is safer to test on a slice of real traffic. These changes affect behavior throughout the app in ways that are hard to wrap in a flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure configuration changes&lt;/strong&gt;. Changes to server tuning, connection pool sizes, caching behavior — these need to run on real infrastructure to measure their effect. A flag in application code can’t surface OS-level or infrastructure-level impacts.&lt;/p&gt;

&lt;p&gt;For everything else — new UI, changed algorithms, new API endpoints, updated business logic — a feature flag rollout is faster to set up, easier to operate, and gives you better targeting control than an infrastructure canary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rollback
&lt;/h2&gt;

&lt;p&gt;The practical advantage of a feature flag over a deployment rollback is speed and granularity. Rolling back a deployment takes minutes and reverts everything in that release. Flipping a flag takes seconds and affects only that feature.&lt;/p&gt;

&lt;p&gt;When something goes wrong at 10% rollout, you open the dashboard and move the slider to 0%. The broken code path stops executing immediately for all users. Then you fix the bug and run the rollout again — without touching anything else that shipped in the same deployment.&lt;/p&gt;

&lt;p&gt;If you want to skip the infrastructure overhead and roll out features gradually with percentage-based targeting, check out Flaggy.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>javascript</category>
      <category>automation</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
