<?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>DEV Community: Flaggy</title>
    <description>The latest articles on DEV Community by Flaggy (@flaggy).</description>
    <link>https://dev.to/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>DEV Community: Flaggy</title>
      <link>https://dev.to/flaggy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flaggy"/>
    <language>en</language>
    <item>
      <title>Canary deployments with feature flags: reduce release risk without the infrastructure</title>
      <dc:creator>Flaggy</dc:creator>
      <pubDate>Mon, 18 May 2026 11:22:03 +0000</pubDate>
      <link>https://dev.to/flaggy/canary-deployments-with-feature-flags-reduce-release-risk-without-the-infrastructure-26nm</link>
      <guid>https://dev.to/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%2Fd059bhym260iyq24wo7r.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%2Fd059bhym260iyq24wo7r.png" alt=" "&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;
  
  
  Targeting canaries at specific users 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: define a segment of internal users or beta testers and enable the flag for that segment before any percentage rollout.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://flaggy.io" rel="noopener noreferrer"&gt;Flaggy&lt;/a&gt;:&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 enabled 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 3 segments — enough for an internal team, a beta group, and one more. If your rollout workflow needs more than that, 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;&lt;a href="https://flaggy.io" rel="noopener noreferrer"&gt;Flaggy’s&lt;/a&gt; free plan supports unlimited flags — there’s no cost to adding a rollout flag to every significant feature you ship.&lt;/p&gt;

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