<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>ConfigCat Blog Blog</title>
        <link>https://configcat.com/blog/</link>
        <description>ConfigCat Blog Blog</description>
        <lastBuildDate>Fri, 12 Jun 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2026 ConfigCat.</copyright>
        <item>
            <title><![CDATA[Feature Flag Ownership: How Product and Engineering Should Share Control]]></title>
            <link>https://configcat.com/blog/feature-flag-ownership/</link>
            <guid>https://configcat.com/blog/feature-flag-ownership/</guid>
            <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Who should own feature flags? Learn how Product and Engineering can share responsibility for implementation, rollouts, permissions, rollback, and cleanup.]]></description>
            <content:encoded><![CDATA[<p>Feature flags are one of those tools everyone loves… until it’s time to decide who actually controls them.</p>
<p>Should Engineering keep them because they built the feature? Should Product take over because they’re responsible for launches and customers? Or should both teams share ownership, set some clear rules, and avoid turning every rollout into a small internal debate?</p>
<p>The honest answer is: both Product and Engineering should own <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer" class="">feature flags</a>, but not in the same way.</p>
<p>Engineering should own the technical side: implementation, safe defaults, stability, and rollback. Product should own the rollout side: launch timing, user targeting, customer exposure, and experiments.</p>
<p>That sounds simple enough. But in real life, this is where things often get messy. So let’s break it down.</p>
<img alt="Feature flag ownership cover" src="https://configcat.com/blog/assets/feature-flag-ownership/feature-flag-ownership-done-right-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-feature-flag-ownership-matters">Why Feature Flag Ownership Matters<a href="https://configcat.com/blog/feature-flag-ownership/#why-feature-flag-ownership-matters" class="hash-link" aria-label="Direct link to Why Feature Flag Ownership Matters" title="Direct link to Why Feature Flag Ownership Matters" translate="no">​</a></h2>
<p>At first glance, feature flags look simple. Just a switch, right? Not quite.</p>
<p>A feature flag can control much more than the visibility of a button. It may control:</p>
<ul>
<li class="">access to a new feature</li>
<li class="">which accounts can join a beta program</li>
<li class="">plan-based or account-based access</li>
<li class="">A/B tests and product experiments</li>
<li class="">percentage rollouts</li>
<li class="">operational kill switches</li>
<li class="">risky backend behavior</li>
<li class="">customer-facing changes in production</li>
</ul>
<p>In one case, changing a flag may reveal a small user interface element. In another, it may affect authentication, payments, permissions, backend processing, or a critical customer workflow.</p>
<p>That is a lot of responsibility for something that looks like a toggle.</p>
<p>When ownership is unclear, familiar problems start appearing:</p>
<ul>
<li class="">A feature is enabled before Support or documentation is ready.</li>
<li class="">Targeting rules are changed without the rest of the team knowing.</li>
<li class="">Product has to ask Engineering to make every small rollout adjustment.</li>
<li class="">A temporary release flag quietly becomes permanent technical debt.</li>
<li class="">Nobody knows who can make an emergency change in production.</li>
<li class="">A customer receives access to something they were not supposed to see yet.</li>
</ul>
<p>None of this is usually dramatic at first. It is more of a slow, annoying kind of confusion. The kind where people start checking old tickets, scrolling through Slack threads, and asking around until someone finally says, “Oh, I think that was created for the beta last quarter.”</p>
<p>Clear ownership prevents that. It tells everyone:</p>
<ul>
<li class="">what the flag is for</li>
<li class="">who owns its implementation</li>
<li class="">who controls its rollout</li>
<li class="">who can change it in production</li>
<li class="">what the safe fallback is</li>
<li class="">when the flag should be removed</li>
</ul>
<p>Good feature flag ownership makes releases calmer. It gives Product more flexibility without making Engineering nervous. It gives Engineering technical control without turning every rollout into a bottleneck. And that is the balance we are looking for.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-engineering-should-own-the-technical-side">Why Engineering Should Own the Technical Side<a href="https://configcat.com/blog/feature-flag-ownership/#why-engineering-should-own-the-technical-side" class="hash-link" aria-label="Direct link to Why Engineering Should Own the Technical Side" title="Direct link to Why Engineering Should Own the Technical Side" translate="no">​</a></h2>
<p>From an engineering perspective, handing over control of feature flags can feel risky, and for good reason.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-feature-flags-live-in-the-code">1. Feature flags live in the code<a href="https://configcat.com/blog/feature-flag-ownership/#1-feature-flags-live-in-the-code" class="hash-link" aria-label="Direct link to 1. Feature flags live in the code" title="Direct link to 1. Feature flags live in the code" translate="no">​</a></h3>
<p>Engineers write the condition logic, define the defaults, and build the safeguards. They are the ones who understand what happens behind the scenes when a flag is turned on or off.</p>
<p>A flag might change a small UI element, but it might also affect backend behavior, permissions, payment flows, or integrations. That difference is not always obvious from the dashboard.</p>
<p>This is why Engineering should decide how a flag is implemented and what the safe default should be.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-theyre-responsible-for-stability">2. They’re responsible for stability<a href="https://configcat.com/blog/feature-flag-ownership/#2-theyre-responsible-for-stability" class="hash-link" aria-label="Direct link to 2. They’re responsible for stability" title="Direct link to 2. They’re responsible for stability" translate="no">​</a></h3>
<p>If a feature flag misbehaves in production, it is usually Engineering that has to investigate. They are the ones checking the logs, looking at errors, rolling back behavior, and trying to understand what changed. So when engineers care about who can change flags, they are not being difficult. They are thinking about risk.</p>
<p>This is especially true for flags that touch sensitive parts of the system, like authentication, billing, permissions, infrastructure, or critical customer workflows.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-environment-drift-drives-them-crazy">3. Environment drift drives them crazy<a href="https://configcat.com/blog/feature-flag-ownership/#3-environment-drift-drives-them-crazy" class="hash-link" aria-label="Direct link to 3. Environment drift drives them crazy" title="Direct link to 3. Environment drift drives them crazy" translate="no">​</a></h3>
<p>There’s also the issue of consistency. Engineers care deeply about environments behaving the same way. If a flag behaves one way in development, another way in staging, and something completely different in production, debugging turns into detective work very quickly. And not the fun kind.</p>
<p>Clear rules around environments, defaults, and rollout paths help avoid that confusion. This is also where good <a href="https://configcat.com/feature-toggle-management/" target="_blank" rel="noopener noreferrer" class="">feature toggle management</a> becomes important. It is not enough to create flags. Teams also need to manage them clearly across environments and over time.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-they-handle-emergency-rollbacks">4. They handle emergency rollbacks<a href="https://configcat.com/blog/feature-flag-ownership/#4-they-handle-emergency-rollbacks" class="hash-link" aria-label="Direct link to 4. They handle emergency rollbacks" title="Direct link to 4. They handle emergency rollbacks" translate="no">​</a></h3>
<p>When things go wrong, Engineering is usually the team handling it.</p>
<p>Kill switches, emergency rollbacks, incident response, quick fixes — this is all part of their world. If a flag creates production risk, Engineering needs the authority to turn it off quickly.</p>
<p>This does not mean Engineering should control every rollout decision. But it does mean they should define the technical boundaries.</p>
<p>From this viewpoint, keeping feature flags under Engineering control feels less like preference and more like a responsibility.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-product-should-own-the-rollout-side">Why Product Should Own the Rollout Side<a href="https://configcat.com/blog/feature-flag-ownership/#why-product-should-own-the-rollout-side" class="hash-link" aria-label="Direct link to Why Product Should Own the Rollout Side" title="Direct link to Why Product Should Own the Rollout Side" translate="no">​</a></h2>
<p>Now switch perspectives. For Product teams, feature flags are not just technical tools. They are how releases actually happen.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-launch-timing-belongs-to-product">1. Launch timing belongs to Product<a href="https://configcat.com/blog/feature-flag-ownership/#1-launch-timing-belongs-to-product" class="hash-link" aria-label="Direct link to 1. Launch timing belongs to Product" title="Direct link to 1. Launch timing belongs to Product" translate="no">​</a></h3>
<p>Features are tied to customer rollouts, campaigns, betas, demos, documentation, support readiness, and sometimes very specific deadlines.</p>
<p>If Product has to ask Engineering every time a feature needs to be enabled, delayed, or adjusted, the process becomes slow very quickly. And that defeats one of the biggest reasons teams use feature flags in the first place.</p>
<p>Feature flags separate deployment from release. Engineering can deploy code when it is ready. Product can release the feature when the business is ready.</p>
<p>This is especially useful in teams that practice <a href="https://configcat.com/progressive-delivery/" target="_blank" rel="noopener noreferrer" class="">progressive delivery</a>, where a release is not treated as one giant moment. Instead, teams roll features out gradually, observe what happens, and expand with more confidence.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-they-understand-user-segmentation">2. They understand user segmentation<a href="https://configcat.com/blog/feature-flag-ownership/#2-they-understand-user-segmentation" class="hash-link" aria-label="Direct link to 2. They understand user segmentation" title="Direct link to 2. They understand user segmentation" translate="no">​</a></h3>
<p>Product teams often know who should see a feature first. Maybe it should go to internal users before customers. Maybe it should be enabled for a few design partners. Maybe it should only be available in one region, for one plan, or for a specific customer segment. That kind of targeting is not just configuration. It is a strategy.</p>
<p>In B2B SaaS, this matters even more. A rollout can affect customer conversations, onboarding, pricing, demos, support tickets, and renewal discussions.</p>
<p>Product has the context to make those decisions.</p>
<p>This is also why feature flags are useful beyond simple on/off releases. They can support beta programs, account-based rollouts, plan-based access, and even <a href="https://configcat.com/fake-door-testing/" target="_blank" rel="noopener noreferrer" class="">fake door testing</a> when teams want to validate demand before fully building a feature.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-experiments-live-in-products-world">3. Experiments live in Product’s world<a href="https://configcat.com/blog/feature-flag-ownership/#3-experiments-live-in-products-world" class="hash-link" aria-label="Direct link to 3. Experiments live in Product’s world" title="Direct link to 3. Experiments live in Product’s world" translate="no">​</a></h3>
<p>A/B tests, gradual rollouts, feature exposure, and product experiments are all part of how Product teams learn. They may want to start an experiment, pause it, expand it, or stop a losing variant. If every change needs an engineering ticket, experimentation slows down.</p>
<p>Feature flags give Product teams the flexibility to learn from real users without turning every change into a deployment. From their point of view, not having control over feature flags slows everything down. And they are right, too.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-best-model-shared-feature-flag-ownership">The Best Model: Shared Feature Flag Ownership<a href="https://configcat.com/blog/feature-flag-ownership/#the-best-model-shared-feature-flag-ownership" class="hash-link" aria-label="Direct link to The Best Model: Shared Feature Flag Ownership" title="Direct link to The Best Model: Shared Feature Flag Ownership" translate="no">​</a></h2>
<p>Feature flag ownership should not be treated as a Product versus Engineering problem. It is a workflow problem. Feature flag ownership has several layers. Someone needs to implement the flag. Someone needs to define the default state. Someone needs to decide who sees the feature. Someone needs to monitor the rollout. Someone needs to turn it off if something goes wrong. And someone needs to remove it when it is no longer needed.</p>
<p>Trying to put all of that on one team usually creates problems.</p>
<p>If Engineering owns everything, Product becomes dependent on Engineering for every rollout change. This slows down launches and makes feature flags feel less useful for non-technical teams.</p>
<p>If Product owns everything, Engineering may lose control over technical risk. This can create production issues, especially when flags affect critical flows or complex backend behavior.</p>
<p>The better model is shared ownership with clear boundaries.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-engineering-owns-safety">1. Engineering owns safety<a href="https://configcat.com/blog/feature-flag-ownership/#1-engineering-owns-safety" class="hash-link" aria-label="Direct link to 1. Engineering owns safety" title="Direct link to 1. Engineering owns safety" translate="no">​</a></h3>
<p>Engineering should be responsible for the technical foundation of each feature flag. That includes implementation, safe defaults, fallback behavior, environment consistency, and rollback options. Engineering should also decide whether a flag is safe for Product to control.</p>
<p>For example, a simple UI visibility flag may be fine for Product to manage directly. A flag that changes authentication, permissions, payments, infrastructure behavior, or backend processing should probably have stricter rules.</p>
<p>Engineering should also own the cleanup of temporary flags. This part is easy to forget, but it matters a lot. A release flag that stays in the codebase long after the feature has launched becomes technical debt. Over time, these old flags make the code harder to read and the system harder to understand.</p>
<p>At some point, nobody remembers whether a flag is still needed. Then everyone becomes afraid to delete it. And that is how a small toggle turns into permanent clutter.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-product-owns-rollout">2. Product owns rollout<a href="https://configcat.com/blog/feature-flag-ownership/#2-product-owns-rollout" class="hash-link" aria-label="Direct link to 2. Product owns rollout" title="Direct link to 2. Product owns rollout" translate="no">​</a></h3>
<p>Product should own the rollout decisions. Once Engineering has implemented the flag safely, Product should be able to decide when and how the feature reaches users. That might mean enabling it for internal users first, then beta customers, then a small percentage of users, and finally everyone.</p>
<p>Product also owns the customer and business context. They know which customers should get early access, which plans should include the feature, and when a rollout should wait because documentation or support material is not ready yet.</p>
<p>A feature flag can be the difference between “we are launching this to everyone today” and “we are giving this to three design partners first, learning from them and expanding next week.”</p>
<p>The second version is usually much safer. And much less stressful.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-everyone-shares-visibility">3. Everyone shares visibility<a href="https://configcat.com/blog/feature-flag-ownership/#3-everyone-shares-visibility" class="hash-link" aria-label="Direct link to 3. Everyone shares visibility" title="Direct link to 3. Everyone shares visibility" translate="no">​</a></h3>
<p>Shared ownership only works if everyone can see what is happening. Feature flags should not become mysterious switches that only one person understands. Both Product and Engineering should know what a flag does, who owns it, whether it is temporary or permanent, who can change it, and what happens if it is turned off.</p>
<p>This visibility is also useful for Customer Success, Support, Sales, and Marketing.</p>
<p>They may not need permission to change flags, but they often need to understand which customers have access to which features. If a customer asks why they can see a new feature but another team member cannot, Customer Success should not have to start a full investigation.</p>
<p>The information should be easy to find. Good visibility prevents confusion. It also makes feature flags more useful across the whole company, not just inside Product and Engineering.</p>
<p>This is one reason why choosing the right <a href="https://configcat.com/feature-flagging-tools/" target="_blank" rel="noopener noreferrer" class="">feature flagging tool</a> matters. The tool should not only help developers evaluate flags in code. It should also give the wider team a clear place to understand rollouts, targeting, permissions, and environments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="different-flags-need-different-owners">Different Flags Need Different Owners<a href="https://configcat.com/blog/feature-flag-ownership/#different-flags-need-different-owners" class="hash-link" aria-label="Direct link to Different Flags Need Different Owners" title="Direct link to Different Flags Need Different Owners" translate="no">​</a></h2>
<p>One reason feature flag ownership can feel complicated is that not all flags are the same.</p>
<p>A temporary release flag is different from a long-term access-control flag. An experiment flag is different from an operational kill switch. Treating all of them the same way usually leads to confusion.</p>
<p>A <strong>release flag</strong> is usually temporary. It hides a feature until the team is ready to launch it. Engineering typically owns the implementation, while Product owns the rollout. Once the feature is fully released and stable, Engineering should remove the flag from the codebase.</p>
<p>An <strong>access-control flag</strong> is usually longer-term. It controls who can use a feature, often based on plan, customer, region, or account. Product may own the business rules, Customer Success may care about specific accounts, and Engineering owns the technical setup. These flags can stay around longer, but they need clear documentation.</p>
<p>An <strong>experiment flag</strong> is used for A/B testing or product experiments. Product or Growth usually owns the experiment, while Engineering owns the implementation. Once the experiment ends, the old variant should be removed. Otherwise, the codebase slowly fills up with past experiments nobody wants to touch.</p>
<p>An <strong>operational flag</strong> is usually owned by Engineering. These flags protect the system. They might disable an external integration, reduce load, or turn off risky behavior during an incident. Product should know they exist, but Engineering should usually control them.</p>
<p>This distinction makes ownership much clearer. Instead of asking who owns all feature flags, teams can ask what type of flag they are dealing with and assign ownership from there.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="common-mistakes-teams-make">Common Mistakes Teams Make<a href="https://configcat.com/blog/feature-flag-ownership/#common-mistakes-teams-make" class="hash-link" aria-label="Direct link to Common Mistakes Teams Make" title="Direct link to Common Mistakes Teams Make" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-giving-everyone-access-to-everything">1. Giving everyone access to everything<a href="https://configcat.com/blog/feature-flag-ownership/#1-giving-everyone-access-to-everything" class="hash-link" aria-label="Direct link to 1. Giving everyone access to everything" title="Direct link to 1. Giving everyone access to everything" translate="no">​</a></h3>
<p>It may feel flexible at first, but not every flag is safe to change without context. A flag may look harmless in the dashboard, but it could affect a sensitive backend process or customer-facing flow. The fix is not to lock everyone out, but to give people the right level of access.</p>
<p>Product should be able to manage rollout flags. Engineering should control high-risk technical flags. Customer-facing teams may only need visibility. Everyone gets what they need, without creating unnecessary risk.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-making-engineering-the-bottleneck-for-every-flag-change">2. Making Engineering the bottleneck for every flag change<a href="https://configcat.com/blog/feature-flag-ownership/#2-making-engineering-the-bottleneck-for-every-flag-change" class="hash-link" aria-label="Direct link to 2. Making Engineering the bottleneck for every flag change" title="Direct link to 2. Making Engineering the bottleneck for every flag change" translate="no">​</a></h3>
<p>If Product has to create a ticket or send a Slack message every time they want to adjust a safe rollout, feature flags lose a lot of their value. They should give teams more flexibility, not create a new dependency.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-forgetting-to-clean-up-old-flags">3. Forgetting to clean up old flags<a href="https://configcat.com/blog/feature-flag-ownership/#3-forgetting-to-clean-up-old-flags" class="hash-link" aria-label="Direct link to 3. Forgetting to clean up old flags" title="Direct link to 3. Forgetting to clean up old flags" translate="no">​</a></h3>
<p>A flag is created for a release, the feature goes live, and then everyone moves on. A few months later, nobody remembers if the flag is still needed. A year later, everyone is afraid to delete it. This is how feature flag debt builds up.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-simple-ownership-checklist">A Simple Ownership Checklist<a href="https://configcat.com/blog/feature-flag-ownership/#a-simple-ownership-checklist" class="hash-link" aria-label="Direct link to A Simple Ownership Checklist" title="Direct link to A Simple Ownership Checklist" translate="no">​</a></h2>
<p>Before creating a new flag, it helps to answer a few basic questions:</p>
<ul>
<li class="">What is this flag for?</li>
<li class="">Is it temporary or permanent?</li>
<li class="">Who owns the technical implementation?</li>
<li class="">Who owns the rollout?</li>
<li class="">Who can change it in production?</li>
<li class="">What is the safe default value?</li>
<li class="">What happens if the flag is turned off?</li>
<li class="">When should it be removed?</li>
</ul>
<p>This does not need to turn into a heavy approval process. The goal is simply to avoid guessing later. If your team can answer these questions, you are already in a much better place.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-who-should-own-feature-flags">So, Who Should Own Feature Flags?<a href="https://configcat.com/blog/feature-flag-ownership/#so-who-should-own-feature-flags" class="hash-link" aria-label="Direct link to So, Who Should Own Feature Flags?" title="Direct link to So, Who Should Own Feature Flags?" translate="no">​</a></h2>
<p>The cleanest answer is this: <strong>Engineering owns implementation and safety. Product owns rollout and exposure. Both teams share visibility and responsibility</strong>.</p>
<p>This model avoids the two extremes. Engineering does not become a bottleneck for every safe rollout change. Product does not get unrestricted control over risky technical behavior. Everyone has more clarity about what is live, what is hidden, what is being tested, and what needs to be cleaned up.</p>
<p>Feature flags work best when they are treated as a shared release tool, not as a territory one team needs to defend.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="final-thoughts">Final Thoughts<a href="https://configcat.com/blog/feature-flag-ownership/#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Feature flag ownership is not really about who gets the power. It is about who has the right context for each decision.</p>
<p>Engineering has the context to make flags safe. Product has the context to decide how and when features should reach users. Customer-facing teams often have the context to understand how those changes affect real customers.</p>
<p>When that context is shared, feature flags become much more than toggles. They become a better way to release software. And that is the whole point. Not more switches. Better releases.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="want-to-make-feature-flag-ownership-easier">Want To Make Feature Flag Ownership Easier?<a href="https://configcat.com/blog/feature-flag-ownership/#want-to-make-feature-flag-ownership-easier" class="hash-link" aria-label="Direct link to Want To Make Feature Flag Ownership Easier?" title="Direct link to Want To Make Feature Flag Ownership Easier?" translate="no">​</a></h2>
<p>If your team wants Product and Engineering to work together on releases without stepping on each other’s toes, <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> can help.</p>
<p>ConfigCat gives teams one shared place to manage feature flags, rollouts, targeting, permissions, and environments. Engineering can keep risky flags protected, Product can manage safe rollout changes, and everyone can see what is happening before, during, and after a release.</p>
<p>You can also connect ConfigCat with the tools your team already uses through <a href="https://configcat.com/docs/integrations/overview/" target="_blank" rel="noopener noreferrer" class="">integrations</a>, join the <a href="https://configcat.com/slack/" target="_blank" rel="noopener noreferrer" class="">ConfigCat Slack Community</a> if you want to talk to others, or reach out to <a href="https://configcat.com/support/" target="_blank" rel="noopener noreferrer" class="">support</a> when you need help.</p>
<p>And because ConfigCat has <a href="https://configcat.com/pricing" target="_blank" rel="noopener noreferrer" class="">transparent pricing</a> and a Forever Free plan with all features included, your whole team can try feature flagging without seat limits.</p>
<p>You can find more information about ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a> and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>software release best practices</category>
        </item>
        <item>
            <title><![CDATA[OpenFeature with ConfigCat: Feature Flags Without Vendor Lock-In]]></title>
            <link>https://configcat.com/blog/feature-flags-without-vendor-lock-in/</link>
            <guid>https://configcat.com/blog/feature-flags-without-vendor-lock-in/</guid>
            <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn what OpenFeature is, how it works with ConfigCat, and how to evaluate feature flags in Node.js using the ConfigCat OpenFeature Provider.]]></description>
            <content:encoded><![CDATA[<p>Feature flags help teams release software with more control. You can roll out features gradually, target specific users, run safer production releases, and turn risky functionality off without redeploying your application.</p>
<p>But once feature flags become part of your release workflow, another question comes up: <strong>should your application code depend directly on one feature flag vendor's SDK?</strong></p>
<p>That is where <a href="https://openfeature.dev/" target="_blank" rel="noopener noreferrer" class="">OpenFeature</a> can help.</p>
<p>In this guide, we'll look at what OpenFeature is, how it works with ConfigCat, and how to use the <a href="https://configcat.com/docs/sdk-reference/openfeature/node" target="_blank" rel="noopener noreferrer" class="">ConfigCat OpenFeature Provider for Node.js</a> in a simple Express API.</p>
<img alt="OpenFeature with ConfigCat: Feature Flags Without Vendor Lock-In Cover" src="https://configcat.com/blog/assets/configcat-openfeature/openfeature-with-configcat-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-openfeature">What Is OpenFeature?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#what-is-openfeature" class="hash-link" aria-label="Direct link to What Is OpenFeature?" title="Direct link to What Is OpenFeature?" translate="no">​</a></h2>
<p><a href="https://openfeature.dev/" target="_blank" rel="noopener noreferrer" class="">OpenFeature</a> is an open specification that provides a unified API for evaluating feature flags, regardless of the feature flag vendor you choose.</p>
<p>Instead of calling a vendor SDK directly throughout your codebase, your application calls the OpenFeature SDK. Then, an <a href="https://openfeature.dev/docs/reference/concepts/provider/" target="_blank" rel="noopener noreferrer" class="">OpenFeature provider</a> connects those calls to your chosen feature flag management system.</p>
<p>For example, when you use OpenFeature with ConfigCat:</p>
<table><thead><tr><th><strong>Layer</strong></th><th><strong>Responsibility</strong></th></tr></thead><tbody><tr><td>OpenFeature SDK</td><td>Provides the standard feature flag evaluation API</td></tr><tr><td>ConfigCat OpenFeature Provider</td><td>Connects OpenFeature to ConfigCat</td></tr><tr><td>ConfigCat</td><td>Manages feature flags, targeting rules, environments, and values</td></tr><tr><td>Your application</td><td>Calls the OpenFeature client to get flag values</td></tr></tbody></table>
<p>OpenFeature does not replace ConfigCat. It standardizes how your application evaluates flags in code, while ConfigCat remains the place where you create, manage, target, and update those flags.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-openfeature-does-and-does-not-do">What OpenFeature Does and Does Not Do<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#what-openfeature-does-and-does-not-do" class="hash-link" aria-label="Direct link to What OpenFeature Does and Does Not Do" title="Direct link to What OpenFeature Does and Does Not Do" translate="no">​</a></h2>
<p>This distinction is important. OpenFeature is not a feature flag dashboard. It is not where product managers create flags, update targeting rules, or review audit logs. It is a standard API layer for evaluating feature flags inside your application.</p>
<table><thead><tr><th><strong>OpenFeature helps you...</strong></th><th><strong>OpenFeature does not...</strong></th></tr></thead><tbody><tr><td>Standardize feature flag evaluation in code</td><td>Replace your feature flag management platform</td></tr><tr><td>Use SDKs and APIs for flag evaluation</td><td>Create or manage feature flags by itself</td></tr><tr><td>Connect to providers such as ConfigCat</td><td>Replace targeting rules, environments, permissions, or audit logs</td></tr><tr><td>Reduce code-level vendor lock-in</td><td>Remove all migration work</td></tr><tr><td>Use tools from the feature flagging ecosystem</td><td>Replace platform-specific management features</td></tr></tbody></table>
<p>In short: <strong>OpenFeature standardizes the code interface. ConfigCat manages the feature flags.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-does-openfeature-work-with-configcat">How Does OpenFeature Work with ConfigCat?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#how-does-openfeature-work-with-configcat" class="hash-link" aria-label="Direct link to How Does OpenFeature Work with ConfigCat?" title="Direct link to How Does OpenFeature Work with ConfigCat?" translate="no">​</a></h2>
<p>OpenFeature adds a vendor abstraction layer on top of your existing feature flagging setup. This is done through <a href="https://openfeature.dev/docs/reference/technologies/sdk-compatibility" target="_blank" rel="noopener noreferrer" class="">SDKs</a> for evaluating feature flags. Feature flag vendors (or open source contributors) are then encouraged to develop <a href="https://openfeature.dev/docs/reference/concepts/provider" target="_blank" rel="noopener noreferrer" class="">OpenFeature providers</a> to connect their SDKs to OpenFeature SDKs. In short, an OpenFeature provider is like a bridge between an app and a feature flag vendor.</p>
<p><a href="https://configcat.com/docs/sdk-reference/openfeature" target="_blank" rel="noopener noreferrer" class="">ConfigCat offers OpenFeature providers</a> for multiple platforms, including Node.js, JavaScript, React, Angular, Go, Java, Python, PHP, Ruby, Swift, .NET, and others. These providers let applications evaluate feature flags through the OpenFeature API while keeping feature management in ConfigCat.</p>
<p>The flow looks like this:</p>
<ol>
<li class="">You create and manage your feature flag in ConfigCat.</li>
<li class="">Your application uses the OpenFeature SDK.</li>
<li class="">The ConfigCat OpenFeature Provider connects OpenFeature to ConfigCat.</li>
<li class="">Your application evaluates the flag through the OpenFeature API.</li>
<li class="">ConfigCat returns the right value based on your targeting rules.</li>
</ol>
<p>This gives you a standardized feature flag API in your code, while still using ConfigCat's dashboard, targeting rules, environments, permissions, and release controls.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-use-openfeature">Why Use OpenFeature?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#why-use-openfeature" class="hash-link" aria-label="Direct link to Why Use OpenFeature?" title="Direct link to Why Use OpenFeature?" translate="no">​</a></h2>
<p>OpenFeature is useful when you want a more standardized approach to feature flag evaluation.</p>
<p>Here are the main benefits.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="less-code-level-vendor-lock-in">Less code-level vendor lock-in<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#less-code-level-vendor-lock-in" class="hash-link" aria-label="Direct link to Less code-level vendor lock-in" title="Direct link to Less code-level vendor lock-in" translate="no">​</a></h3>
<p>Different feature flag tools usually have different SDK methods, data structures, and implementation patterns. If you use those SDKs directly everywhere, switching providers later can require a lot of code changes.</p>
<p>OpenFeature reduces that coupling by giving your application a consistent feature flag API. This does not mean migrations become completely automatic. You may still need to recreate flags, targeting rules, environments, permissions, and workflows in the new platform. But at the code level, OpenFeature can make the transition easier.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-consistent-api-across-teams-and-services">A consistent API across teams and services<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#a-consistent-api-across-teams-and-services" class="hash-link" aria-label="Direct link to A consistent API across teams and services" title="Direct link to A consistent API across teams and services" translate="no">​</a></h3>
<p>If your organization has multiple services, languages, or teams, OpenFeature can help standardize how everyone evaluates feature flags.</p>
<p>Instead of each team learning a different SDK style, they can work with the same OpenFeature concepts:</p>
<ul>
<li class="">providers</li>
<li class="">clients</li>
<li class="">evaluation context</li>
<li class="">flag evaluation methods</li>
<li class="">hooks</li>
<li class="">events</li>
</ul>
<p>This is especially useful in larger engineering teams or companies with polyglot architectures.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="access-to-the-openfeature-ecosystem">Access to the OpenFeature ecosystem<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#access-to-the-openfeature-ecosystem" class="hash-link" aria-label="Direct link to Access to the OpenFeature ecosystem" title="Direct link to Access to the OpenFeature ecosystem" translate="no">​</a></h3>
<p>OpenFeature is part of the <a href="https://www.cncf.io/projects/openfeature/" target="_blank" rel="noopener noreferrer" class="">Cloud Native Computing Foundation (CNCF)</a> ecosystem. The project was accepted into CNCF on June 17, 2022, and moved to the Incubating maturity level on November 21, 2023.</p>
<p>Because it is open and community-driven, teams can build shared tooling around feature flagging. For example, OpenFeature can work with observability-related concepts such as <a href="https://openfeature.dev/docs/reference/concepts/hooks/" target="_blank" rel="noopener noreferrer" class="">hooks</a>, including <a href="https://opentelemetry.io/" target="_blank" rel="noopener noreferrer" class="">OpenTelemetry</a>-related use cases.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="easier-experimentation-with-providers">Easier experimentation with providers<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#easier-experimentation-with-providers" class="hash-link" aria-label="Direct link to Easier experimentation with providers" title="Direct link to Easier experimentation with providers" translate="no">​</a></h3>
<p>OpenFeature can also be useful when evaluating feature flag platforms. Since your application talks to the OpenFeature API, you can test different providers with fewer changes to your business logic.</p>
<p>This can be useful if you are comparing vendors, migrating away from an in-house solution, or moving from another feature flag platform to ConfigCat.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-should-you-use-openfeature">When Should You Use OpenFeature?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#when-should-you-use-openfeature" class="hash-link" aria-label="Direct link to When Should You Use OpenFeature?" title="Direct link to When Should You Use OpenFeature?" translate="no">​</a></h2>
<p>OpenFeature is a good fit if:</p>
<ul>
<li class="">You want a vendor-agnostic feature flag API.</li>
<li class="">You are migrating between feature flag providers.</li>
<li class="">You want to standardize feature flag evaluation across multiple services.</li>
<li class="">You work with several languages or frameworks.</li>
<li class="">You want to reduce code-level coupling to one provider.</li>
<li class="">You want to use tools from the OpenFeature ecosystem.</li>
<li class="">You are building or replacing an in-house feature flag system.</li>
</ul>
<p>It can also help if your team wants to keep the application code clean and consistent while still using a managed feature flag platform.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-might-you-not-need-openfeature">When Might You Not Need OpenFeature?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#when-might-you-not-need-openfeature" class="hash-link" aria-label="Direct link to When Might You Not Need OpenFeature?" title="Direct link to When Might You Not Need OpenFeature?" translate="no">​</a></h2>
<p>OpenFeature is helpful, but it is not always necessary. You may prefer using the ConfigCat SDK directly if:</p>
<ul>
<li class="">You are happy with one feature flag provider.</li>
<li class="">You want the simplest possible setup.</li>
<li class="">You do not need a vendor abstraction layer.</li>
<li class="">Your team wants direct access to ConfigCat-specific SDK features.</li>
<li class="">You are building a small project where portability is not a concern.</li>
</ul>
<p>OpenFeature is most useful when portability and standardization matter. If your team wants the simplest possible setup or needs direct access to vendor-specific SDK features, using the native feature flag platform SDK may be the better fit.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="openfeature-provider-vs-native-configcat-sdk-what-is-the-difference">OpenFeature Provider vs. Native ConfigCat SDK: What Is the Difference?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#openfeature-provider-vs-native-configcat-sdk-what-is-the-difference" class="hash-link" aria-label="Direct link to OpenFeature Provider vs. Native ConfigCat SDK: What Is the Difference?" title="Direct link to OpenFeature Provider vs. Native ConfigCat SDK: What Is the Difference?" translate="no">​</a></h2>
<p>OpenFeature providers and native ConfigCat SDKs are not exactly the same, because they serve different purposes.</p>
<p>OpenFeature provides a standardized abstraction layer. It covers the common functionality shared across feature flag providers, which makes your application code more portable.</p>
<p>The native ConfigCat SDKs give you direct access to the full ConfigCat-specific feature set.</p>
<p>For basic use cases, such as evaluating on/off feature flags, OpenFeature works well. You can evaluate boolean flags, pass an evaluation context, and use ConfigCat <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer" class="">targeting rules</a> behind the scenes.</p>
<p>However, some advanced or ConfigCat-specific capabilities are not exposed directly through the OpenFeature API. Examples include:</p>
<ul>
<li class=""><code>getAllKeys</code></li>
<li class="">ConfigCat-specific hooks</li>
<li class="">snapshots</li>
<li class="">online/offline mode</li>
</ul>
<p>The ConfigCat OpenFeature provider also exposes the underlying ConfigCat client through a <code>configCatClient</code> property. This means you can still access ConfigCat-specific functionality when needed.</p>
<p>The trade-off is portability. The more your application relies on ConfigCat-specific methods through the underlying client, the less vendor-agnostic your OpenFeature integration becomes.</p>
<table><thead><tr><th><strong>Use OpenFeature when...</strong></th><th><strong>Use the native ConfigCat SDK when...</strong></th></tr></thead><tbody><tr><td>You want a standard feature flag API</td><td>You want full access to ConfigCat SDK features</td></tr><tr><td>You mainly evaluate flags</td><td>You need ConfigCat-specific methods</td></tr><tr><td>You want portability across providers</td><td>You are fully committed to ConfigCat</td></tr><tr><td>Your use case is simple on/off flags or targeting</td><td>You need advanced SDK behavior such as snapshots or online/offline mode</td></tr></tbody></table>
<p>A good rule of thumb: <strong>use OpenFeature when standardization and portability matter. Use the native ConfigCat SDK when you want the full ConfigCat SDK feature set with fewer abstraction limits.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="demo-use-openfeature-with-configcat-in-nodejs">Demo: Use OpenFeature with ConfigCat in Node.js<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#demo-use-openfeature-with-configcat-in-nodejs" class="hash-link" aria-label="Direct link to Demo: Use OpenFeature with ConfigCat in Node.js" title="Direct link to Demo: Use OpenFeature with ConfigCat in Node.js" translate="no">​</a></h2>
<p>Let's build a <a href="https://github.com/configcat-labs/configcat-openfeature-sample" target="_blank" rel="noopener noreferrer" class="">simple Node.js API using Express</a> that returns a filtered list of AI models based on the user sent in the request.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">cURL http://localhost:3000/models -H "x-user-email: tom@whisker.co" | jq</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">[</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "GPT 3.5 Turbo",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "standard"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "Claude Haiku",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "standard"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "Llama 2 7B",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "standard"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "GPT-4o",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "pro"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "Claude Sonnet 3.5",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "pro"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "Llama 3.1 405B",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "pro"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">]</span><br></div></code></pre></div></div>
<p>I'll show you how to use OpenFeature's standardized evaluation context when evaluating a feature flag. This is useful for targeting users based on attributes such as name, email, and country. For example, showing users with an <code>@whisker.co</code> email address a list of pro-AI models, while others see standard AI models.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>An <a href="https://openfeature.dev/docs/reference/concepts/evaluation-context" target="_blank" rel="noopener noreferrer" class="">evaluation context</a> according to OpenFeature's specification is a container for arbitrary contextual data that can be used as a basis for feature flag evaluation. In ConfigCat, this translates to the <a href="https://configcat.com/docs/sdk-reference/js/node/#user-object" target="_blank" rel="noopener noreferrer" class="">User Object</a>.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-a-feature-flag-in-configcat">Step 1: Create a Feature Flag in ConfigCat<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#step-1-create-a-feature-flag-in-configcat" class="hash-link" aria-label="Direct link to Step 1: Create a Feature Flag in ConfigCat" title="Direct link to Step 1: Create a Feature Flag in ConfigCat" translate="no">​</a></h3>
<ol>
<li class="">
<p><a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">Sign in</a> to ConfigCat, or <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">sign up</a> if you don't have an account.</p>
</li>
<li class="">
<p>Create a feature flag with the following details.</p>
<ul>
<li class=""><strong>Name</strong>: Enable Pro Models</li>
<li class=""><strong>Key</strong>: <code>enableProModels</code></li>
<li class=""><strong>Hint</strong>: Enable pro AI models for users with an @whisker.co email address</li>
</ul>
</li>
<li class="">
<p>Click <code>+ IF</code>, then click <code>Target users</code>.</p>
<p>You'll see two sections: an <code>IF</code> section for configuring the condition and a <code>THEN</code> section for setting the feature flag's value based on the condition.</p>
</li>
<li class="">
<p>In the <code>IF</code> section, select <code>Email</code> as the comparison attribute, then select <code>ENDS WITH ANY OF (hashed)</code> as the comparator.</p>
</li>
<li class="">
<p>Enter <code>@whisker.co</code> in the field next to the comparator, then turn on the feature flag in the <code>THEN</code> section below. Click <code>SAVE &amp; PUBLISH CHANGES</code>.</p>
</li>
</ol>
<img class="zoomable" alt="Feature flag with email targeting" src="https://configcat.com/blog/assets/configcat-openfeature/feature-flag-with-email-targeting_192dpi.png" width="1102" height="449" decoding="async" loading="lazy">
<p>Now that we've configured the feature flag, let's move on to the code.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-install-configcat-and-openfeature">Step 2: Install ConfigCat and OpenFeature<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#step-2-install-configcat-and-openfeature" class="hash-link" aria-label="Direct link to Step 2: Install ConfigCat and OpenFeature" title="Direct link to Step 2: Install ConfigCat and OpenFeature" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h4>
<ul>
<li class="">Node.js v18+</li>
<li class="">Basic understanding of Node.js and Express</li>
</ul>
<p>To use ConfigCat and OpenFeature together, we'll need to install ConfigCat's <a href="https://configcat.com/docs/sdk-reference/openfeature/node/" target="_blank" rel="noopener noreferrer" class="">OpenFeature Provider for Node.js</a>. ConfigCat's Node SDK and OpenFeature's Server SDK will be automatically downloaded alongside the provider.</p>
<ol>
<li class="">Open your terminal, create a new directory, and install the provider.</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mkdir configcat-openfeature-nodejs</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm init -y</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install express</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">touch index.js</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm i @openfeature/config-cat-provider</span><br></div></code></pre></div></div>
<ol start="2">
<li class="">Import the provider and OpenFeature server SDK in <code>index.js</code>.</li>
</ol>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@openfeature/config-cat-provider'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">OpenFeature</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@openfeature/server-sdk'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<ol start="3">
<li class="">Create the ConfigCat provider with your <a href="https://app.configcat.com/sdkkey" target="_blank" rel="noopener noreferrer" class="">ConfigCat SDK key</a>. Then, set the provider and create an OpenFeature client.</li>
</ol>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Create a provider with your SDK key</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> provider </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token maybe-class-name">ConfigCatProvider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">create</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'YOUR-CONFIGCAT-SDK-KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Initialize the provider</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token maybe-class-name">OpenFeature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">setProviderAndWait</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">provider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Create a client.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token maybe-class-name">OpenFeature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p><code>ConfigCatProvider.create</code> creates a ConfigCat client with the specific SDK key. The <code>setProviderAndWait</code> method sets ConfigCat as the source of feature flag values and ensures the provider is ready before we begin using it. Finally, <code>OpenFeature.getClient</code> creates a client that uses the set provider to evaluate feature flags.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-create-the-api-endpoint">Step 3: Create the API Endpoint<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#step-3-create-the-api-endpoint" class="hash-link" aria-label="Direct link to Step 3: Create the API Endpoint" title="Direct link to Step 3: Create the API Endpoint" translate="no">​</a></h3>
<p>I'll create a <code>/models</code> endpoint that returns a list of AI models. Depending on the email address supplied in the request header, we'll return a list of pro-AI models if the flag evaluates to true and the standard list otherwise.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'/models'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">req</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> email </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> req</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">headers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'x-user-email'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">email</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">status</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">400</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">message</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Email required'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> context </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">targetingKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// required</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">email</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> email</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> modelsListEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getBooleanValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token string" style="color:rgb(195, 232, 141)">'enableProModels'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">modelsListEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> proModels </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> db</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getModels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'pro'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Returning pro models...'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">proModels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> standardModels </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> db</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getModels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'standard'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Returning standard models...'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">standardModels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>The <code>context</code> object stores a unique targeting key and the user's email. To evaluate the flag using OpenFeature, I passed the flag key, a default value, and the context. As stated earlier, the ConfigCat Node.js provider automatically transforms <code>context</code> into a ConfigCat <a href="https://configcat.com/docs/targeting/user-object/" target="_blank" rel="noopener noreferrer" class="">User object</a>, which ConfigCat will use to determine whether the user's email matches the condition set in the targeting rule.</p></div></div>
<p>Finally, I added a condition to return the appropriate list of models based on the feature flag's value. Let's see if it works.</p>
<p>When a user is supplied with an email address like: <code>tom@whisker.co</code> the response would be:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">cURL http://localhost:3000/models -H "x-user-email: tom@whisker.co" | jq</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">[</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "GPT-4o",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "pro"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "Claude Sonnet 3.5",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "pro"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": "Llama 3.1 405B",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    "type": "pro"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-use-configcat-with-openfeature">Why Use ConfigCat with OpenFeature?<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#why-use-configcat-with-openfeature" class="hash-link" aria-label="Direct link to Why Use ConfigCat with OpenFeature?" title="Direct link to Why Use ConfigCat with OpenFeature?" translate="no">​</a></h2>
<p>OpenFeature gives you a standardized evaluation API. ConfigCat gives you the feature flag management layer behind it.</p>
<p>Together, they give you vendor-agnostic feature flag evaluation in code without giving up a managed dashboard, targeting rules, environments, permissions, and release controls.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="recap">Recap<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#recap" class="hash-link" aria-label="Direct link to Recap" title="Direct link to Recap" translate="no">​</a></h2>
<p>OpenFeature is useful when you want a standardized, vendor-agnostic way to evaluate feature flags in your application code. ConfigCat provides the feature flag management layer behind it, including targeting rules, environments, values, and release controls.</p>
<p>In this guide, we covered:</p>
<ul>
<li class="">what OpenFeature is</li>
<li class="">what OpenFeature does and does not do</li>
<li class="">how OpenFeature works with ConfigCat</li>
<li class="">when OpenFeature is useful</li>
<li class="">how OpenFeature providers differ from native ConfigCat SDKs</li>
<li class="">how to use the ConfigCat OpenFeature Provider for Node.js</li>
</ul>
<p>OpenFeature is a good fit when portability and standardization matter. If you want the simplest direct integration or need ConfigCat-specific SDK features, the native ConfigCat SDK may be the better choice.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="next-steps">Next Steps<a href="https://configcat.com/blog/feature-flags-without-vendor-lock-in/#next-steps" class="hash-link" aria-label="Direct link to Next Steps" title="Direct link to Next Steps" translate="no">​</a></h2>
<p>To explore the broader OpenFeature ecosystem, visit <a href="https://openfeature.dev/" target="_blank" rel="noopener noreferrer" class="">OpenFeature.dev</a> or join the <a href="https://cloud-native.slack.com/archives/C0344AANLA1" target="_blank" rel="noopener noreferrer" class="">OpenFeature Slack channel</a> to get the latest updates.</p>
<p>If you want to try feature flags with ConfigCat, you can start with the <a href="https://configcat.com/pricing/" target="_blank" rel="noopener noreferrer" class="">Forever Free plan</a> and connect your first flag through OpenFeature or a native<a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class=""> ConfigCat SDK</a>.</p>
<p>For more on feature flags, check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, and <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>.</p>]]></content:encoded>
            <category>open source</category>
            <category>OpenFeature</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags Explained: How They Work, Why They Matter]]></title>
            <link>https://configcat.com/blog/feature-flags-explained/</link>
            <guid>https://configcat.com/blog/feature-flags-explained/</guid>
            <pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[What are feature flags and how do they work? Learn how to use feature flags for safe releases, A/B testing, and gradual rollouts with real examples.]]></description>
            <content:encoded><![CDATA[<p>You’ve probably heard the term feature flag, maybe in a pull request review, a deployment postmortem, or a job description. The concept sounds simple: turn features on and off without redeploying code. But once you start working with them, you realize there’s a lot more to it than a boolean in a config file. They fundamentally change how you ship software.</p>
<p>This guide explains what feature flags actually are, how they work under the hood, when to use them, when not to use them, how to test them properly, how to manage them across teams, and how to avoid the organizational problems that turn a helpful tool into a maintenance burden.</p>
<img alt="Feature flags explained cover" src="https://configcat.com/blog/assets/feature-flags-explained/feature-flags-explained-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-feature-flags">What Are Feature Flags?<a href="https://configcat.com/blog/feature-flags-explained/#what-are-feature-flags" class="hash-link" aria-label="Direct link to What Are Feature Flags?" title="Direct link to What Are Feature Flags?" translate="no">​</a></h2>
<p><a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer" class="">Feature flags</a> (also called <em>feature toggles</em>) are a way to control application behavior without changing code.</p>
<p>A feature flag is simply a conditional in your code whose value is controlled externally (usually from a dashboard or configuration service) and can be changed at runtime.</p>
<p>Here’s the simplest possible version in Python:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> configcatclient</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcatclient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"#YOUR-SDK-KEY#"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"new_checkout_flow"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    render_new_checkout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    render_legacy_checkout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>The important part isn't the <code>if</code> statement. It's where the value comes from. The <code>"new_checkout_flow" </code>flag isn't hardcoded. It's controlled externally, often from a dashboard. That means someone can change it instantly, without touching the code or triggering a deployment.</p>
<p>That separation is what makes feature flags so powerful. The code is deployed, but the behavior is still flexible.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="see-feature-flags-in-action">See Feature Flags in Action<a href="https://configcat.com/blog/feature-flags-explained/#see-feature-flags-in-action" class="hash-link" aria-label="Direct link to See Feature Flags in Action" title="Direct link to See Feature Flags in Action" translate="no">​</a></h3>
<p>Sometimes it's easier to understand feature flags by seeing them work. In this example, the code reads multiple feature flags (like dark mode or sales banner). Toggling them instantly changes the UI without any redeployment.</p>
<p>Try toggling the flags to see how the application updates in real time.</p>
<div class="animation-container"><div class="wrapper"><div class="control-box shadow"><h3>All Feature Flags</h3><div class="toggle-container"><div class="switcher-container"><p>Dark mode</p><label class="switch form-label"><input type="checkbox" autocomplete="off"><span class="slider round"></span></label></div><div class="switcher-container"><p>Sales mode</p><label class="switch form-label"><input type="checkbox" autocomplete="off"><span class="slider round"></span></label></div><div class="switcher-container"><p>Holiday mode</p><label class="switch form-label"><input type="checkbox" autocomplete="off"><span class="slider round"></span></label></div></div><img src="https://configcat.com/blog/assets/animation/logo.svg" alt="logo" class="logo"></div><div class="ui-animation shadow"><img src="https://configcat.com/blog/assets/animation/orange-header.svg" alt="Orange header" class="img_back-ui header"><img src="https://configcat.com/blog/assets/animation/dark-header.svg" alt="Dark header" class="img_back-ui dark"><img src="https://configcat.com/blog/assets/animation/sales-banner.svg" alt="Sales banner" class="img_back-ui banner"><img src="https://configcat.com/blog/assets/animation/ui-elements.svg" alt="UI elements" class="img_back-ui elements"><img src="https://configcat.com/blog/assets/animation/cat-with-hat.svg" alt="Cat with hat" class="img_back-ui hat-cat"></div></div><div id="code-box"><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">ConfigCat.js</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"#SDK-KEY#"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> darkMode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"darkMode"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> salesMode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"salesMode"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> snowEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"snowEnabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">darkMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function" style="color:rgb(130, 170, 255)">enableDarkTheme</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">salesMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function" style="color:rgb(130, 170, 255)">showSalesBanner</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snowEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function" style="color:rgb(130, 170, 255)">startSnowAnimation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div></div></div>
<p>This is the core idea of feature flags: the code stays the same, but behavior changes instantly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-feature-flags-matter-deployment-vs-release">Why Feature Flags Matter: Deployment vs. Release<a href="https://configcat.com/blog/feature-flags-explained/#why-feature-flags-matter-deployment-vs-release" class="hash-link" aria-label="Direct link to Why Feature Flags Matter: Deployment vs. Release" title="Direct link to Why Feature Flags Matter: Deployment vs. Release" translate="no">​</a></h2>
<p>Before feature flags, deploying code and releasing a feature were the same event. You merge, you deploy, the feature is live. If something breaks, you roll back the entire deployment, not just the broken feature but everything that shipped with it.</p>
<p>Feature flags change that. <strong>Deployment</strong> is the act of getting code into production. <strong>Release</strong> is the act of making a feature visible to users. With feature flags, these happen independently:</p>
<ul>
<li class="">You deploy on Tuesday with the flag OFF, the code is live but nothing has changed for users.</li>
<li class="">You release on Friday by flipping the flag. No deployment, no risk window.</li>
<li class="">If something breaks, you flip the flag back. Users return to the previous behavior in seconds, no rollback required, even on a Saturday, without needing to call in a developer or DevOps.</li>
</ul>
<img alt="With or without feature flags" src="https://configcat.com/blog/assets/feature-flags-explained/with-or-without-feature-flags_192dpi.png" width="1366" height="768" decoding="async" loading="lazy" class="zoomable">
<p>This is called <strong>separating deployment from release</strong> and it's a core principle of continuous delivery. Research from the <a href="https://dora.dev/research/" target="_blank" rel="noopener noreferrer" class="">DORA State of DevOps report</a> consistently shows that high-performing engineering teams deploy more frequently and have lower change failure rates. Feature flags are one of the key practices that make this possible.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-feature-flag-evaluation-works-under-the-hood">How Feature Flag Evaluation Works Under the Hood<a href="https://configcat.com/blog/feature-flags-explained/#how-feature-flag-evaluation-works-under-the-hood" class="hash-link" aria-label="Direct link to How Feature Flag Evaluation Works Under the Hood" title="Direct link to How Feature Flag Evaluation Works Under the Hood" translate="no">​</a></h2>
<p>Understanding how feature flags are evaluated isn't just an implementation detail, it directly affects performance, consistency, and how you design your system.</p>
<p>From the outside, a flag check looks simple. Under the hood, a few important things happen to make it fast and reliable.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-the-sdk-fetches-and-caches-configuration">1. The SDK fetches and caches configuration<a href="https://configcat.com/blog/feature-flags-explained/#1-the-sdk-fetches-and-caches-configuration" class="hash-link" aria-label="Direct link to 1. The SDK fetches and caches configuration" title="Direct link to 1. The SDK fetches and caches configuration" translate="no">​</a></h3>
<p>When your app starts, the SDK downloads the current configuration from the flag management service and stores it locally.</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Go example — SDK initialization</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">client </span><span class="token operator" style="color:rgb(137, 221, 255)">:=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">NewCustomClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    SDKKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"#YOUR-SDK-KEY#"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    PollingMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">AutoPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    PollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Second </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">defer</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<p>The important thing: flag evaluation does <strong>not</strong> make a network call on every check. The SDK reads from a local in-memory cache. Flag evaluation typically takes microseconds and adds no noticeable latency to your application.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-the-cache-is-updated-in-the-background">2. The cache is updated in the background<a href="https://configcat.com/blog/feature-flags-explained/#2-the-cache-is-updated-in-the-background" class="hash-link" aria-label="Direct link to 2. The cache is updated in the background" title="Direct link to 2. The cache is updated in the background" translate="no">​</a></h3>
<p>The SDK periodically polls the configuration service for updates. The interval is configurable, commonly 30 to 60 seconds. Some SDKs also support webhook-based invalidation for near-instant propagation. In serverless environments like AWS Lambda, where in-memory state doesn’t persist between invocations, a shared external cache (such as Redis) is the better pattern.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-targeting-rules-are-evaluated-locally">3. Targeting rules are evaluated locally<a href="https://configcat.com/blog/feature-flags-explained/#3-targeting-rules-are-evaluated-locally" class="hash-link" aria-label="Direct link to 3. Targeting rules are evaluated locally" title="Direct link to 3. Targeting rules are evaluated locally" translate="no">​</a></h3>
<p>When your code checks a flag, the SDK evaluates it against the user context you provide.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Java example — passing user context for targeting</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> user </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">newBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">email</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"alice@company.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">custom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">Map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">of</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"country"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"US"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"subscriptionPlan"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"pro"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">build</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"user_123"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">boolean</span><span class="token plain"> isEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">Boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token keyword" style="font-style:italic">class</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"new_dashboard_layout"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>The SDK evaluates the flag against the targeting rules you've defined, such as:</p>
<ul>
<li class="">user-specific targeting</li>
<li class="">segment rules based on attributes like plan or region</li>
<li class="">percentage rollout rules</li>
</ul>
<p>If none of those rules match, it falls back to the default value you provide.</p>
<p>The percentage rollout is worth understanding specifically, The SDK doesn’t use random chance. Instead, it uses a deterministic hashing algorithm based on the user's identifier and the flag key to assign each user to a stable bucket.</p>
<p>This means the result is always the same for the same user, no matter when or where the evaluation happens.</p>
<ul>
<li class="">hash(userId + flagKey) % 100 → consistent bucket between 0–99</li>
<li class="">if bucket &lt; rolloutPercentage → flag is ON for this user</li>
</ul>
<p>Because of this, feature flag evaluation is both stateless and predictable:</p>
<ul>
<li class="">no user data needs to be stored server-side</li>
<li class="">no session tracking is required</li>
<li class="">and no user will randomly switch between experiences</li>
</ul>
<p>A user who is part of the 20% rollout today will still be part of that same 20% tomorrow, across sessions, devices, and even platforms.</p>
<p>This is what makes <a href="https://configcat.com/canary-testing/" target="_blank" rel="noopener noreferrer" class="">canary releases</a> reliable. When you gradually roll out a feature, you're not exposing it to a different group of users each time. You're expanding a stable group which makes it much easier to monitor behavior, detect issues, and build confidence before going to 100%</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-your-code-executes-the-correct-path">4. Your code executes the correct path<a href="https://configcat.com/blog/feature-flags-explained/#4-your-code-executes-the-correct-path" class="hash-link" aria-label="Direct link to 4. Your code executes the correct path" title="Direct link to 4. Your code executes the correct path" translate="no">​</a></h3>
<p>The SDK returns the value, your code branches, done. The entire process from calling getValue to executing the right code path takes under a millisecond in any long-running application.</p>
<img alt="How code is executed" src="https://configcat.com/blog/assets/feature-flags-explained/how-code-is-executed_192dpi.png" width="1366" height="768" decoding="async" loading="lazy" class="zoomable">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-four-types-of-feature-flags">The Four Types of Feature Flags<a href="https://configcat.com/blog/feature-flags-explained/#the-four-types-of-feature-flags" class="hash-link" aria-label="Direct link to The Four Types of Feature Flags" title="Direct link to The Four Types of Feature Flags" translate="no">​</a></h2>
<p>Not all flags serve the same purpose. Understanding the types helps you manage their<a href="https://configcat.com/blog/2024/01/30/feature-flag-retirement/#feature-flag-lifecycle-timing-their-retirement" target="_blank" rel="noopener noreferrer" class=""> lifecycle </a>correctly because each type has a different expected lifespan and a different risk profile. The four main types of feature flags you'll encounter in production are release flags, experiment flags, operational flags (kill switches), and permission flags.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-release-flags">1. Release flags<a href="https://configcat.com/blog/feature-flags-explained/#1-release-flags" class="hash-link" aria-label="Direct link to 1. Release flags" title="Direct link to 1. Release flags" translate="no">​</a></h3>
<p><strong>Purpose</strong>: Gradual rollout of a new feature<br>
<strong>Lifespan</strong>: Short (days or weeks)</p>
<p>Release flags are the most common type. They exist to separate deployment from release and enable gradual rollouts. Once a feature is at 100% and stable, the flag should be removed, leaving it in the codebase creates flag debt.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-experiment-flags">2. Experiment flags<a href="https://configcat.com/blog/feature-flags-explained/#2-experiment-flags" class="hash-link" aria-label="Direct link to 2. Experiment flags" title="Direct link to 2. Experiment flags" translate="no">​</a></h3>
<p><strong>Purpose</strong>: A/B testing and production experimentation<br>
<strong>Lifespan</strong>: Duration of the experiment</p>
<p>Experiment flags return multiple variants rather than a simple boolean. Each variant maps to a different experience, and the distribution across your user base lets you measure which performs better.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// JavaScript — experiment flag with multiple variants</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">renderCheckout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> checkoutVariant </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"checkout_redesign_experiment"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"control"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    user</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Returns: "control" | "single_page" | "progressive"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">checkoutVariant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"single_page"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function" style="color:rgb(130, 170, 255)">renderSinglePageCheckout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword control-flow" style="font-style:italic">break</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"progressive"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function" style="color:rgb(130, 170, 255)">renderProgressiveCheckout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword control-flow" style="font-style:italic">break</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword module" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function" style="color:rgb(130, 170, 255)">renderLegacyCheckout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>In practice, this means you can test completely different user experiences without separate deployments or feature branches.</p>
<p>This is also the mechanism behind <a href="https://configcat.com/fake-door-testing/" target="_blank" rel="noopener noreferrer" class="">fake door testing</a>, where you expose a feature concept to users before building it and measure real demand.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-operational-flags-kill-switches">3. Operational flags (Kill switches)<a href="https://configcat.com/blog/feature-flags-explained/#3-operational-flags-kill-switches" class="hash-link" aria-label="Direct link to 3. Operational flags (Kill switches)" title="Direct link to 3. Operational flags (Kill switches)" translate="no">​</a></h3>
<p><strong>Purpose</strong>: Disable unstable or expensive functionality instantly during incidents<br>
<strong>Lifespan</strong>: Permanent or long-term</p>
<p>Operational flags, often called kill switches, are designed to be flipped under pressure. When something goes wrong in production, you don't want to deploy a fix, you want to turn the problem off.</p>
<p>The default value is critical here. If the flag service is unreachable, the system should fail safe by disabling the risky functionality.</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Go — kill switch for an external recommendation service</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">useRecommendations </span><span class="token operator" style="color:rgb(137, 221, 255)">:=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">GetBoolValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"recommendations_engine_enabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// safe default: disable if flag service is unreachable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> useRecommendations </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    products</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getPersonalizedRecommendations</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">userID</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// External API call</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        products </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultProductList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// fallback on error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    products </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultProductList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// fast, local path</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>This pattern is particularly valuable for <a href="https://configcat.com/site-reliability-engineers/" target="_blank" rel="noopener noreferrer" class="">site reliability engineers</a>. A well-placed kill switch means the response to a production incident is a dashboard toggle, not an emergency deployment at 2 am.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-permission-flags">4. Permission flags<a href="https://configcat.com/blog/feature-flags-explained/#4-permission-flags" class="hash-link" aria-label="Direct link to 4. Permission flags" title="Direct link to 4. Permission flags" translate="no">​</a></h3>
<p><strong>Purpose</strong>: Control access to features based on user plan, role, or group<br>
<strong>Lifespan</strong>: Long-term or permanent</p>
<p>Unlike release flags, permission flags aren’t removed after a rollout. They become part of how your product works, controlling who gets access to what.</p>
<p>This is where feature flags start to overlap with product logic, not just release strategy. They're often used for things like premium features, roll-based access, or region-specific functionality.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Java — permission flag gating a premium feature</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> user </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">newBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">custom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">Map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">of</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"plan"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> currentUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getSubscriptionPlan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">build</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">currentUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">boolean</span><span class="token plain"> canExportData </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">Boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token keyword" style="font-style:italic">class</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"csv_export_enabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">canExportData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ResponseEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">status</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">403</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">body</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Upgrade to Pro to export data"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// proceed with export</span><br></div></code></pre></div></div>
<p>Because these flags tend to live longer, they require clear ownership, proper documentation, and regular review.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-feature-flag-lifecycle">The Feature Flag Lifecycle<a href="https://configcat.com/blog/feature-flags-explained/#the-feature-flag-lifecycle" class="hash-link" aria-label="Direct link to The Feature Flag Lifecycle" title="Direct link to The Feature Flag Lifecycle" translate="no">​</a></h2>
<p>Every flag passes through stages. Understanding the lifecycle helps you avoid the two most common failure modes: flags that never get removed, and flags removed before it’s safe to do so.</p>
<p>Done right, feature flags don't just help you release safely. They help you operate cleanly over time.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-create">1. Create<a href="https://configcat.com/blog/feature-flags-explained/#1-create" class="hash-link" aria-label="Direct link to 1. Create" title="Direct link to 1. Create" translate="no">​</a></h3>
<p>Before writing a line of code, define the flag in your management tool and document:</p>
<ul>
<li class="">What does this flag control?</li>
<li class="">Who owns it?</li>
<li class="">What is the safe default if evaluation fails?</li>
<li class="">When should it be deleted?</li>
</ul>
<p>That last question is the one most teams skip. Answering it at creation time makes cleanup decisions obvious later instead of ambiguous forever.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-deploy">2. Deploy<a href="https://configcat.com/blog/feature-flags-explained/#2-deploy" class="hash-link" aria-label="Direct link to 2. Deploy" title="Direct link to 2. Deploy" translate="no">​</a></h3>
<p>The feature ships to production with the flag set to <code>False</code>. From the user’s perspective, nothing has changed. From an engineering perspective, the code is already live and running in your production environment.</p>
<p>This is a meaningful safety step that’s easy to undervalue. Bugs that only appear under real production conditions (memory leaks, race conditions, performance issues under real load) can surface before any user is affected.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-roll-out">3. Roll out<a href="https://configcat.com/blog/feature-flags-explained/#3-roll-out" class="hash-link" aria-label="Direct link to 3. Roll out" title="Direct link to 3. Roll out" translate="no">​</a></h3>
<p>Once you're confident the system is stable, you start exposing the feature to real users gradually.</p>
<p>A typical rollout might look like this:</p>
<table><thead><tr><th>Stage</th><th>Audience</th><th>Duration</th><th>What to watch</th></tr></thead><tbody><tr><td>Internal</td><td>Employees only</td><td>1–2 days</td><td>Crashes, basic functionality</td></tr><tr><td>Canary</td><td>1–5% of users</td><td>3–5 days</td><td>Error rates, latency, conversion</td></tr><tr><td>Partial</td><td>10–50% of users</td><td>3–7 days</td><td>User behavior, support volume</td></tr><tr><td>Full</td><td>100%</td><td>—</td><td>Confirm stability, schedule cleanup</td></tr></tbody></table>
<p>Define what “healthy” looks like before you start. Rollback decisions made against pre-defined criteria are fast and confident. Rollback decisions made by gut feel in the middle of an incident are slow and stressful.</p>
<p>You can also combine rollout with <a href="https://configcat.com/soak-testing/" target="_blank" rel="noopener noreferrer" class="">soak testing</a>, letting the feature run at a fixed percentage for an extended period to catch issues that only emerge over time.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-monitor">4. Monitor<a href="https://configcat.com/blog/feature-flags-explained/#4-monitor" class="hash-link" aria-label="Direct link to 4. Monitor" title="Direct link to 4. Monitor" translate="no">​</a></h3>
<p>A flag change you can’t measure is a flag change you can’t safely make. Before enabling a flag for real users, make sure you can answer:</p>
<ul>
<li class="">Which users are receiving which variant?</li>
<li class="">How do error rates differ between flag states?</li>
<li class="">What's happening to key business metrics?</li>
</ul>
<p>Feature flags don't replace observability, they depend on it. Without monitoring, feature flags increase risk instead of reducing it. Most teams integrate with tools like <a href="https://www.datadoghq.com/" target="_blank" rel="noopener noreferrer" class="">Datadog</a>, <a href="https://newrelic.com/" target="_blank" rel="noopener noreferrer" class="">New Relic</a>, or <a href="https://sentry.io/" target="_blank" rel="noopener noreferrer" class="">Sentry </a>to track the impact of each rollout step in real time.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-clean-up">5. Clean up<a href="https://configcat.com/blog/feature-flags-explained/#5-clean-up" class="hash-link" aria-label="Direct link to 5. Clean up" title="Direct link to 5. Clean up" translate="no">​</a></h3>
<p>Once a feature is at 100% and stable, the flag has served its purpose. Remove it from the flag management tool and from the codebase. Leaving old flags behind increases complexity, makes code harder to read, and creates long-term maintenance risk.</p>
<img alt="Feature flag lifecycle" src="https://configcat.com/blog/assets/feature-flags-explained/feature-flag-lifecycle_192dpi.png" width="1366" height="768" decoding="async" loading="lazy" class="zoomable">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="feature-flag-use-cases">Feature Flag Use Cases<a href="https://configcat.com/blog/feature-flags-explained/#feature-flag-use-cases" class="hash-link" aria-label="Direct link to Feature Flag Use Cases" title="Direct link to Feature Flag Use Cases" translate="no">​</a></h2>
<p>Feature flags are one of those tools that seem simple at first, but once you start using them, they quietly spread across everything. What begins as a safe rollout mechanism turns into a way to experiment, control risk, and even reshape how teams collaborate.</p>
<p>Here are the most common (and most valuable) ways teams actually use them in practice.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="gradual-rollouts">Gradual rollouts<a href="https://configcat.com/blog/feature-flags-explained/#gradual-rollouts" class="hash-link" aria-label="Direct link to Gradual rollouts" title="Direct link to Gradual rollouts" translate="no">​</a></h3>
<p>Instead of releasing a feature to everyone at once, you start small.</p>
<p>Release to 1% of users, watch your error dashboards, then expand to 10%, 50%, 100%. A bug that would have hit your entire user base now affects a fraction of them, and you catch it while you can still react calmly.</p>
<p>This is closely related to <a href="https://configcat.com/ring-deployment/" target="_blank" rel="noopener noreferrer" class="">ring deployment</a>, a pattern where you define explicit rings of users and move through them with explicit validation gates.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="canary-release">Canary release<a href="https://configcat.com/blog/feature-flags-explained/#canary-release" class="hash-link" aria-label="Direct link to Canary release" title="Direct link to Canary release" translate="no">​</a></h3>
<p>A canary release is a gradual rollout specifically designed to catch regressions before they affect your full user base. You deploy to a “canary” cohort (typically 1-5% of users), monitor key metrics and only proceed if the canary is healthy.</p>
<p>The important part isn't the percentage. It's the discipline of validating before expanding.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="ab-testing-and-experimentation">A/B testing and experimentation<a href="https://configcat.com/blog/feature-flags-explained/#ab-testing-and-experimentation" class="hash-link" aria-label="Direct link to A/B testing and experimentation" title="Direct link to A/B testing and experimentation" translate="no">​</a></h3>
<p>Feature flags don't just control exposure, they also enable learning. Different users can see different versions of a feature, and you can measure which one performs better. That could be a checkout flow, a pricing page, or even a button label.</p>
<p>The key advantage of server-side experimentation is that it happens before the response reaches the user:</p>
<ul>
<li class="">No flicker</li>
<li class="">No layout shifts</li>
<li class="">No dependency on JavaScript loading</li>
</ul>
<p>You're measuring real behavior from the moment the request hits your system.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="kill-switches-for-production-incidents">Kill switches for production incidents<a href="https://configcat.com/blog/feature-flags-explained/#kill-switches-for-production-incidents" class="hash-link" aria-label="Direct link to Kill switches for production incidents" title="Direct link to Kill switches for production incidents" translate="no">​</a></h3>
<p>When something breaks in production, the fastest resolution is disabling the feature, not redeploying, not rolling back, not waiting for a hotfix to pass CI. A kill switch turns a potential 30-minute incident into a 30-second one. This is testing in production with a safety net.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="infrastructure-migrations">Infrastructure migrations<a href="https://configcat.com/blog/feature-flags-explained/#infrastructure-migrations" class="hash-link" aria-label="Direct link to Infrastructure migrations" title="Direct link to Infrastructure migrations" translate="no">​</a></h3>
<p>This is one of the most underused applications of feature flags, and one of the highest-value. When migrating from one database, API, or third-party service to another, you can use a flag to route traffic gradually from the old system to the new one:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Python — infrastructure migration flag</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use_new_payments_api </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"payments_stripe_v2"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> user_object</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> use_new_payments_api</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> stripe_v2_client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">charge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> currency</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> token</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> stripe_v1_client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">charge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> currency</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> token</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="environment-based-releases">Environment-based releases<a href="https://configcat.com/blog/feature-flags-explained/#environment-based-releases" class="hash-link" aria-label="Direct link to Environment-based releases" title="Direct link to Environment-based releases" translate="no">​</a></h3>
<p>Different behavior across environments without code changes:</p>
<table><thead><tr><th>Environment</th><th>Flag State</th><th>Purpose</th></tr></thead><tbody><tr><td>Development</td><td>Enabled</td><td>Developers can work with the full feature</td></tr><tr><td>Staging</td><td>Enabled</td><td>QA validates the full experience</td></tr><tr><td>Production</td><td>Disabled</td><td>Users see stable behavior until release</td></tr></tbody></table>
<p>This means the same codebase runs everywhere, with environment-specific behavior controlled externally.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="user-targeting-and-dogfooding">User targeting and dogfooding<a href="https://configcat.com/blog/feature-flags-explained/#user-targeting-and-dogfooding" class="hash-link" aria-label="Direct link to User targeting and dogfooding" title="Direct link to User targeting and dogfooding" translate="no">​</a></h3>
<p>Enable a feature for internal employees before any external users. Let them find the bugs, give feedback, and validate workflows before customers see anything. This dogfooding or champagne brunch approach is one of the highest-quality pre-release testing methods available because it runs in your actual production environment with real data.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="feature-flags-vs-configuration-files">Feature Flags vs. Configuration Files<a href="https://configcat.com/blog/feature-flags-explained/#feature-flags-vs-configuration-files" class="hash-link" aria-label="Direct link to Feature Flags vs. Configuration Files" title="Direct link to Feature Flags vs. Configuration Files" translate="no">​</a></h2>
<p>At first glance, feature flags can look like just another form of configuration. After all, both control how your application behaves without changing the core logic. But the difference shows up the moment you need to move fast.</p>
<p>Traditional configuration files require modifying a file, often redeploying or restarting the service, and they apply the same value to every user. They weren't designed for frequent change, and they weren't designed for experimentation.</p>
<p>Feature flags were. They let you change behavior at runtime, target specific users, and roll things out gradually, all without touching your codebase or triggering a deployment.</p>
<p>Here's how they compare in practice:</p>
<table><thead><tr><th>Capability</th><th>Config file</th><th>Feature flag</th></tr></thead><tbody><tr><td>Change without redeployment</td><td>Sometimes</td><td>Always</td></tr><tr><td>Per-user targeting</td><td>No</td><td>Yes</td></tr><tr><td>Percentage rollouts</td><td>No</td><td>Yes</td></tr><tr><td>Instant propagation</td><td>No</td><td>Yes</td></tr><tr><td>Audit trail</td><td>No</td><td>Yes (with a tool)</td></tr><tr><td>Safe default on outage</td><td>Manual</td><td>Built-in</td></tr><tr><td>Evaluation analytics</td><td>No</td><td>Yes</td></tr></tbody></table>
<p>The key distinction isn’t just runtime vs. deployment-time. It’s that feature flags are designed to be changed frequently, often by non-engineers, with built-in targeting logic and a full history of who changed what and when.</p>
<p>Configuration files are static by nature. Feature flags are dynamic by design.</p>
<p>If you're just setting a value once and rarely touching it again, a config file is perfectly fine. But the moment you need control, experimentation, or safe releases, you're no longer dealing with configuration. You're dealing with <a href="https://configcat.com/blog/2022/01/14/progressive-delivery/" target="_blank" rel="noopener noreferrer" class="">progressive delivery</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-not-to-use-feature-flags">When NOT to Use Feature Flags<a href="https://configcat.com/blog/feature-flags-explained/#when-not-to-use-feature-flags" class="hash-link" aria-label="Direct link to When NOT to Use Feature Flags" title="Direct link to When NOT to Use Feature Flags" translate="no">​</a></h2>
<p>Feature flags are powerful, but they're not a universal solution. Used in the wrong places, they add complexity without adding value.</p>
<p>Knowing when <em>not</em> to use them is just as important as knowing when to reach for them.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="long-term-configuration-management">Long-term configuration management<a href="https://configcat.com/blog/feature-flags-explained/#long-term-configuration-management" class="hash-link" aria-label="Direct link to Long-term configuration management" title="Direct link to Long-term configuration management" translate="no">​</a></h3>
<p>If a value changes rarely, doesn’t need user targeting, and doesn’t need an audit trail, an environment variable or config file is simpler and more appropriate.</p>
<p>Not everything needs to be dynamic. In fact, forcing rarely changing values into feature flags often makes things harder to reason about, not easier. Feature flags are designed for change. If there's no change, there's no benefit.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="secrets-and-credentials">Secrets and credentials<a href="https://configcat.com/blog/feature-flags-explained/#secrets-and-credentials" class="hash-link" aria-label="Direct link to Secrets and credentials" title="Direct link to Secrets and credentials" translate="no">​</a></h3>
<p>API keys, database password, OAuth secrets - these belong in dedicated secrets managers, not feature flags.</p>
<p>Feature flags are evaluated in ways that may expose their values to clients (especially in frontend or mobile environments). That makes them the wrong place for anything sensitive.
If leaking it would be a security incident, it shouldn't be a flag.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="core-business-logic-that-should-never-be-disabled">Core business logic that should never be disabled<a href="https://configcat.com/blog/feature-flags-explained/#core-business-logic-that-should-never-be-disabled" class="hash-link" aria-label="Direct link to Core business logic that should never be disabled" title="Direct link to Core business logic that should never be disabled" translate="no">​</a></h3>
<p>A feature flag implies optionality. If turning something off would fundamentally break your application, it shouldn't be behind a flag in the first place.</p>
<p>Authentication, core data persistence and payment processing are foundational parts of your system. Treating them as optional introduces risk, not flexibility.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="replacing-proper-access-control">Replacing proper access control<a href="https://configcat.com/blog/feature-flags-explained/#replacing-proper-access-control" class="hash-link" aria-label="Direct link to Replacing proper access control" title="Direct link to Replacing proper access control" translate="no">​</a></h3>
<p>Feature flags are often used to <em>gate</em> features, but they are not a replacement for authorization.</p>
<p>A flag can decide <em>who sees a feature</em>. It should not decide <em>who is allowed to perform an action</em>. If you rely solely on flags to enforce security boundaries without proper server-side checks, you don't have feature control. You have a security gap.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="hiding-permanently-broken-features">Hiding permanently broken features<a href="https://configcat.com/blog/feature-flags-explained/#hiding-permanently-broken-features" class="hash-link" aria-label="Direct link to Hiding permanently broken features" title="Direct link to Hiding permanently broken features" translate="no">​</a></h3>
<p>This one happens more often than teams admit. A feature is buggy, so it gets turned off. Weeks pass. Then months. The flag stays false and the code stays in the system.</p>
<p>At that point, the flag isn't helping anymore. It's hiding unfinished work and adding noise to your codebase.</p>
<p>Feature flags are meant for controlled release, not permanent deferral. If a feature isn't coming back, remove it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="who-uses-feature-flags-across-the-organization">Who Uses Feature Flags Across the Organization<a href="https://configcat.com/blog/feature-flags-explained/#who-uses-feature-flags-across-the-organization" class="hash-link" aria-label="Direct link to Who Uses Feature Flags Across the Organization" title="Direct link to Who Uses Feature Flags Across the Organization" translate="no">​</a></h2>
<p>Feature flags often start with developers and expand from there. Once the infrastructure is in place, the control over releases starts to move beyond engineering. What used to require a deployment becomes a decision. And decisions don't always belong to developers.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="product-managers">Product managers<a href="https://configcat.com/blog/feature-flags-explained/#product-managers" class="hash-link" aria-label="Direct link to Product managers" title="Direct link to Product managers" translate="no">​</a></h3>
<p>For product managers, feature flags turn release timing into a controllable variable. They can decide who sees a feature, when it goes live, and how it's introduced. That means launches can align with campaigns, experiments can run without engineering bottlenecks, and features can be enabled exactly when they create the most impact.</p>
<p>A product manager flipping a flag during a live demo isn't a workaround. It's the system doing what it was designed to do.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="qa-engineers">QA engineers<a href="https://configcat.com/blog/feature-flags-explained/#qa-engineers" class="hash-link" aria-label="Direct link to QA engineers" title="Direct link to QA engineers" translate="no">​</a></h3>
<p>For QA, feature flags remove one of the biggest constraints in testing: environment limitations.</p>
<p>Features can be enabled in staging or even production for internal users, without affecting real customers. Specific scenarios, edge cases, or user segments can be tested on demand, without waiting for a new deployment.</p>
<p>Testing becomes more flexible, and closer to real-world conditions.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="marketing-and-growth-teams">Marketing and growth teams<a href="https://configcat.com/blog/feature-flags-explained/#marketing-and-growth-teams" class="hash-link" aria-label="Direct link to Marketing and growth teams" title="Direct link to Marketing and growth teams" translate="no">​</a></h3>
<p>For marketing and growth teams, feature flags unlock experimentation without dependency. Campaigns don't have to wait for releases. Landing page variations can be tested in real time. Features can be enabled for specific regions, audiences, or cohorts as part of a broader strategy.</p>
<p>This is where feature flags start to overlap with growth tooling, not replacing it, but enabling faster iteration.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="site-reliability-engineers">Site reliability engineers<a href="https://configcat.com/blog/feature-flags-explained/#site-reliability-engineers" class="hash-link" aria-label="Direct link to Site reliability engineers" title="Direct link to Site reliability engineers" translate="no">​</a></h3>
<p>For SREs, feature flags are a control mechanism under pressure. Operational flags, often called kill switches, allow teams to degrade non-critical functionality gracefully when systems are under stress. Instead of firefighting with emergency deployments, they can stabilize the system with a single toggle.</p>
<p>Disabling a recommendation engine or a heavy background process during peak load isn't just a technical decision. It's a reliability strategy.</p>
<p>What ties all of this together is not just the technology, but the shift in ownership.</p>
<p>Feature flags allow engineering to build the system, while giving other teams controlled ways to operate within it. That's what a <a href="https://configcat.com/feature-flagging-tools/" target="_blank" rel="noopener noreferrer" class="">feature flagging tool</a> makes possible: centralized control with distributed decision-making.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-to-bring-in-a-feature-flag-management-tool">When to Bring in a Feature Flag Management Tool<a href="https://configcat.com/blog/feature-flags-explained/#when-to-bring-in-a-feature-flag-management-tool" class="hash-link" aria-label="Direct link to When to Bring in a Feature Flag Management Tool" title="Direct link to When to Bring in a Feature Flag Management Tool" translate="no">​</a></h2>
<p>You can implement basic feature flags yourself, a value in a database, a simple API, a cache layer. This works until it doesn’t.</p>
<p>The challenges that appear at scale are organizational, not technical. A homegrown system gives you toggles. A management platform gives you control.</p>
<table><thead><tr><th>Capability</th><th>Why it matters</th></tr></thead><tbody><tr><td>Audit log</td><td>Every flag change is traceable: who, what, when</td></tr><tr><td>Evaluation analytics</td><td>Know if a flag is still being evaluated before deleting</td></tr><tr><td>Targeting and segmentation</td><td>User-specific and percentage rollouts without custom infrastructure</td></tr><tr><td>Server-side SDKs</td><td>Backend enforcement across languages</td></tr><tr><td>Lifecycle management</td><td>Surface zombie flags before they accumulate</td></tr><tr><td>Role-based access</td><td>Non-engineers can control flags safely without touching code</td></tr></tbody></table>
<p>The right time to bring in a tool is before the organizational problems appear. If more than one team is creating flags, or you have more than 20-30 active flags, manual management is already a liability.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="final-thoughts">Final Thoughts<a href="https://configcat.com/blog/feature-flags-explained/#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Feature flags might start as a small technical decision, but they quickly become part of how you build, release, and operate software.</p>
<p>They give you control over what users see and when they see it. They let you test ideas safely, roll things out gradually, and react quickly when something doesn't go as planned. Over time, they shift releases from risky events to controlled decisions.</p>
<p>Of course, like any powerful tool, they come with responsibility. Used well, they make your system more flexible and your team more confident. Used poorly, they create noise and complexity. The goal isn't to flag everything, it's to use flags where they actually give you an advantage.</p>
<p>If you're ready to see how feature flags work in practice, you can get started with <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">ConfigCat's Forever Free plan</a> in minutes and make your next release a little less stressful.</p>
<p>For more information, check out ConfigCat's <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">website</a>. You can also stay up to date with the newest developments by following ConfigCat on <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, <a href="https://x.com/ConfigCat" target="_blank" rel="noopener noreferrer" class="">X</a>, or <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>.</p>]]></content:encoded>
            <category>feature management</category>
            <category>feature flags</category>
            <category>how to</category>
            <category>SDK</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags in Microservices and Serverless Architecture (AWS Lambda and .NET)]]></title>
            <link>https://configcat.com/blog/feature-flags-aws-lambda-dotnet/</link>
            <guid>https://configcat.com/blog/feature-flags-aws-lambda-dotnet/</guid>
            <pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Implement ConfigCat feature flags in AWS Lambda and .NET microservices to control, test, and gradually roll out features in serverless architectures.]]></description>
            <content:encoded><![CDATA[<p>In monolithic applications, every change requires redeploying the entire system. Now, imagine pushing a payment processing update to your e-commerce platform during peak traffic. A bug slips through. You deploy a fix. That fix introduces another issue. Suddenly, you're rolling back the whole application under pressure.</p>
<p><a href="https://martinfowler.com/articles/microservices.html" target="_blank" rel="noopener noreferrer" class="">Microservices</a> reduce that blast radius by breaking systems into smaller, independently deployable services. When you combine microservices with <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer" class="">feature flags</a>, you gain something even more powerful: the ability to change production behavior without redeploying code.  If one service misbehaves, you don't redeploy. You disable the feature. You stabilize and fix forward. That level of runtime control is what makes feature flags essential in distributed systems.</p>
<p>In this guide, we'll explore how feature flags work in microservices and serverless architectures, and walk through a practical example using AWS Lambda, .NET, Redis, and ConfigCat.</p>
<img alt="Feature Flags in Microservices and Serverless Architecture (with AWS Lambda and .NET)" src="https://configcat.com/blog/assets/feature-flags-aws-lambda-dotnet/feature-flags-in-aws-lambda-dotnet-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-feature-flags-in-microservices">What Are Feature Flags in Microservices?<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#what-are-feature-flags-in-microservices" class="hash-link" aria-label="Direct link to What Are Feature Flags in Microservices?" title="Direct link to What Are Feature Flags in Microservices?" translate="no">​</a></h2>
<p>Feature flags (also called feature toggles) are configuration switches that allow developers to turn application features on or off without redeploying code. In a microservices architecture, this becomes extremely powerful.</p>
<p>Instead of coordinating releases across multiple services, teams can:</p>
<ul>
<li class="">Deploy code with features disabled</li>
<li class="">Gradually enable functionality when ready</li>
<li class="">Disable problematic features instantly</li>
</ul>
<p>Feature flags are commonly used for:</p>
<ul>
<li class="">Progressive rollouts</li>
<li class="">Canary releases</li>
<li class="">A/B testing</li>
<li class="">Kill switches for production incidents</li>
<li class="">User segmentation</li>
</ul>
<p>This decouples deployment from release, which is one of the key principles of modern DevOps practices.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-feature-flags-work-in-microservices-architecture">How Feature Flags Work in Microservices Architecture<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#how-feature-flags-work-in-microservices-architecture" class="hash-link" aria-label="Direct link to How Feature Flags Work in Microservices Architecture" title="Direct link to How Feature Flags Work in Microservices Architecture" translate="no">​</a></h2>
<p><strong>A microservices architecture is a design approach in which a single application is composed of many loosely coupled, independently deployable services</strong>. Each service typically focuses on a single business capability, such as:</p>
<ul>
<li class="">Product catalog</li>
<li class="">Authentication</li>
<li class="">Payments</li>
<li class="">Checkout</li>
<li class="">Order processing</li>
</ul>
<p>These services communicate through APIs.</p>
<p>While this architecture improves scalability and team autonomy, it also introduces release coordination challenges.</p>
<p>For example:</p>
<ul>
<li class="">Team A (Payments) is ready to release a new feature.</li>
<li class="">Team B (Invoicing) isn't ready yet.</li>
</ul>
<p>Without feature flags, Team A waits. Deployment timing becomes coupled across teams.</p>
<p>With feature flags, Team A can deploy the new code with the feature disabled. When the dependency is ready, the flag is enabled remotely. No coordinated deployment window, no cross-team blocking</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-safe-feature-rollout">Example: Safe Feature Rollout<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#example-safe-feature-rollout" class="hash-link" aria-label="Direct link to Example: Safe Feature Rollout" title="Direct link to Example: Safe Feature Rollout" translate="no">​</a></h3>
<p>Imagine you introduce a "Buy Now with One Click" button to your <em>Checkout Service</em>, but this feature depends on data from another microservice, the <em>Shipping Service</em>. If the Shipping Service starts lagging or crashes, you can quickly revert to the standard multi-step checkout without rolling back any code—simply by toggling the flag OFF.</p>
<p>Beyond simple ON/OFF control, they enable:</p>
<ul>
<li class=""><a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">Targeting</a> specific users, regions, or environments.</li>
<li class="">A/B testing new behavior.</li>
<li class=""><a href="https://configcat.com/blog/2022/01/14/progressive-delivery/" target="_blank" rel="noopener noreferrer" class="">Progressive Rollouts</a> (canary releases).</li>
</ul>
<p>In a microservices architecture, this provides a safety net for features that depend on each other. You can release incrementally, validate safely, and limit exposure when things go wrong.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="microservices-vs-serverless-architecture">Microservices vs Serverless Architecture<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#microservices-vs-serverless-architecture" class="hash-link" aria-label="Direct link to Microservices vs Serverless Architecture" title="Direct link to Microservices vs Serverless Architecture" translate="no">​</a></h2>
<p>Although the terms are sometimes used together, microservices and serverless refer to different things.</p>
<table><thead><tr><th>Concept</th><th>Description</th></tr></thead><tbody><tr><td>Microservices</td><td>How an application is structured</td></tr><tr><td>Serverless</td><td>How services are deployed and executed</td></tr></tbody></table>
<p>Serverless platforms like <a href="https://aws.amazon.com/pm/lambda/" target="_blank" rel="noopener noreferrer" class="">AWS Lambda</a> are often used to run microservices because they provide:</p>
<ul>
<li class="">Automatic scaling</li>
<li class="">No server management</li>
<li class="">Pay-per-execution pricing</li>
<li class="">Fast deployment cycles</li>
</ul>
<p>Each microservice can run as its own set of Lambda functions.</p>
<p>When combined with feature flags, this architecture allows teams to control behavior remotely across distributed services without redeploying functions.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="challenges-of-using-feature-flags-in-serverless-aws-lambda">Challenges of Using Feature Flags in Serverless (AWS Lambda)<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#challenges-of-using-feature-flags-in-serverless-aws-lambda" class="hash-link" aria-label="Direct link to Challenges of Using Feature Flags in Serverless (AWS Lambda)" title="Direct link to Challenges of Using Feature Flags in Serverless (AWS Lambda)" translate="no">​</a></h2>
<p>Lambda functions are short-lived by design. They boot up, handle a request, and return.</p>
<p>AWS may reuse execution environments between invocations (warm starts), but you cannot rely on in-memory state being preserved. <a href="https://aws.amazon.com/blogs/compute/understanding-and-remediating-cold-starts-an-aws-lambda-perspective/" target="_blank" rel="noopener noreferrer" class="">Cold starts</a> create a fresh execution environment with no cached data. This matters for feature flag evaluation.</p>
<p>If your Lambda function fetches feature flag configuration from an external API on every invocation:</p>
<ol>
<li class=""><strong>Latency:</strong> Network calls before each execution slow everything down.</li>
<li class=""><strong>Cost &amp; Limits:</strong> You'll burn through API quotas and rack up data transfer fees.</li>
</ol>
<p>With feature flags in serverless architectures, you need to play by different rules. Depending on how quickly your Lambdas need to react to feature flag changes, you can cache your feature flag data and refresh it periodically to avoid serving stale flags.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-implement-feature-flags-in-aws-lambda-with-net">How to Implement Feature Flags in AWS Lambda with .NET<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#how-to-implement-feature-flags-in-aws-lambda-with-net" class="hash-link" aria-label="Direct link to How to Implement Feature Flags in AWS Lambda with .NET" title="Direct link to How to Implement Feature Flags in AWS Lambda with .NET" translate="no">​</a></h2>
<p>Let's walk through a practical example of integrating feature flags in a .NET AWS Lambda function using <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a>.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>In Lambda environments specifically, the in-memory cache used by the polling modes: <a href="https://configcat.com/docs/sdk-reference/dotnet/#auto-polling-default" target="_blank" rel="noopener noreferrer" class="">Auto polling</a>, <a href="https://configcat.com/docs/sdk-reference/dotnet/#lazy-loading" target="_blank" rel="noopener noreferrer" class="">Lazy loading</a>, and <a href="https://configcat.com/docs/sdk-reference/dotnet/#manual-polling" target="_blank" rel="noopener noreferrer" class="">Manual polling</a> may not be applicable to every use case, since the cache can be empty on each Lambda invocation. In such scenarios, opting for a <a href="https://configcat.com/docs/sdk-reference/dotnet/#using-custom-cache-implementation" target="_blank" rel="noopener noreferrer" class="">custom cache implementation</a> is often recommended. Alternatively, if your Lambdas use multiple SDK instances, leveraging a <a href="https://configcat.com/docs/advanced/caching/#shared-cache" target="_blank" rel="noopener noreferrer" class="">Shared cache</a> can be optimal.</p></div></div>
<p>Here's how to set it up.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h3>
<p>To follow this tutorial, you will need a few tools installed and accounts set up. Don't worry, free tiers work perfectly for everything here.</p>
<ul>
<li class=""><strong>A ConfigCat Account:</strong> You can sign up for a <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">forever free account here</a>.</li>
<li class=""><strong>An AWS Account:</strong> You will need access to the AWS Console and a user with permissions to create Lambda functions.</li>
<li class=""><strong>A Redis Instance:</strong> For this tutorial, you can use a free <a href="https://redis.io/try-free" target="_blank" rel="noopener noreferrer" class="">Redis Cloud</a> database to quickly obtain a connection string. <strong>Amazon ElastiCache</strong> is typically used in production AWS environments.</li>
<li class=""><strong>The .NET SDK:</strong> We are using .NET 10.0, which you can <a href="https://dotnet.microsoft.com/download" target="_blank" rel="noopener noreferrer" class="">download here</a>.</li>
<li class=""><strong>Command Line Tools:</strong>
<ul>
<li class=""><strong><a href="https://aws.amazon.com/cli/" target="_blank" rel="noopener noreferrer" class="">AWS CLI</a>:</strong> configured with your credentials (<code>aws configure</code>).</li>
<li class=""><strong>AWS Lambda Tools for .NET:</strong>.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-a-feature-flag-in-configcat">Step 1: Create a Feature Flag in ConfigCat<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#step-1-create-a-feature-flag-in-configcat" class="hash-link" aria-label="Direct link to Step 1: Create a Feature Flag in ConfigCat" title="Direct link to Step 1: Create a Feature Flag in ConfigCat" translate="no">​</a></h3>
<p>Before writing code, we need a flag to control.</p>
<ol>
<li class="">Log in to the <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat Dashboard</a>.</li>
<li class="">Create a new Feature Flag with the name <code>My Feature Flag</code> and key name <strong>isMyFeatureEnabled</strong>.</li>
<li class="">Turn the feature <strong>ON</strong> (so we can verify it works later).</li>
</ol>
<img alt="My Feature Flag On" src="https://configcat.com/blog/assets/feature-flags-aws-lambda-dotnet/my-feature-flag-on_192dpi.png" width="1366" height="384" decoding="async" loading="lazy" class="zoomable">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-setting-up-the-net-project">Step 2: Setting Up the .NET Project<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#step-2-setting-up-the-net-project" class="hash-link" aria-label="Direct link to Step 2: Setting Up the .NET Project" title="Direct link to Step 2: Setting Up the .NET Project" translate="no">​</a></h3>
<p>We will use the .NET CLI to create a lightweight Lambda function. Open your terminal or PowerShell and run the following commands:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Create a new empty Lambda function</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet new lambda</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">EmptyFunction </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain">n ConfigCatLambdaDemo</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Navigate into the project directory</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">cd ConfigCatLambdaDemo</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Install the ConfigCat Client SDK and Redis Client</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet add package ConfigCat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Client</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet add package StackExchange</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Redis</span><br></div></code></pre></div></div>
<p>This installs the necessary NuGet packages to handle .NET feature flags and the Redis cache integration.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-implementing-the-shared-cache-redis">Step 3: Implementing the Shared Cache (Redis)<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#step-3-implementing-the-shared-cache-redis" class="hash-link" aria-label="Direct link to Step 3: Implementing the Shared Cache (Redis)" title="Direct link to Step 3: Implementing the Shared Cache (Redis)" translate="no">​</a></h3>
<p>This is the most critical part of this tutorial. In standard apps, internal caching works fine. But in AWS Lambda, in-memory state is not guaranteed to persist between invocations. To prevent your Lambdas from spamming the ConfigCat API on every "Cold Start," we will use <strong>Redis</strong> as a persistent, shared cache.</p>
<p>Open your <code>Function.cs</code> file and replace the content with the following code. This includes a custom <code>RedisCache</code> class that implements ConfigCat's caching interface:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">Amazon</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Lambda</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Core</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCat</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCat</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Client</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCat</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Client</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Cache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">StackExchange</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token attribute target keyword" style="font-style:italic">assembly</span><span class="token attribute punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token attribute"> </span><span class="token attribute class-name" style="color:rgb(255, 203, 107)">LambdaSerializer</span><span class="token attribute attribute-arguments punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token attribute attribute-arguments keyword" style="font-style:italic">typeof</span><span class="token attribute attribute-arguments punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token attribute attribute-arguments type-expression class-name" style="color:rgb(255, 203, 107)">Amazon</span><span class="token attribute attribute-arguments type-expression class-name punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token attribute attribute-arguments type-expression class-name" style="color:rgb(255, 203, 107)">Lambda</span><span class="token attribute attribute-arguments type-expression class-name punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token attribute attribute-arguments type-expression class-name" style="color:rgb(255, 203, 107)">Serialization</span><span class="token attribute attribute-arguments type-expression class-name punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token attribute attribute-arguments type-expression class-name" style="color:rgb(255, 203, 107)">SystemTextJson</span><span class="token attribute attribute-arguments type-expression class-name punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token attribute attribute-arguments type-expression class-name" style="color:rgb(255, 203, 107)">DefaultLambdaJsonSerializer</span><span class="token attribute attribute-arguments punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token attribute attribute-arguments punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">namespace</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCatLambdaDemo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Function</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IConfigCatClient</span><span class="token plain"> _configCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">Function</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Add your real ConfigCat SDK key here or add it as an Environment Variable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> sdkKey </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"your-configcat-sdk-key"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Add your real Redis Connection String here or add it as an Environment Variable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> redisConnectionString </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"your-redis-connection-string"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        _configCatClient </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ConfigCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> options </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ConfigCache </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)">RedisCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">redisConnectionString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">PollingMode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> PollingModes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">AutoPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token named-parameter punctuation" style="color:rgb(199, 146, 234)">pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> TimeSpan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">FromSeconds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">Task</span><span class="token return-type class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token return-type class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">FunctionHandler</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ILambdaContext</span><span class="token plain"> context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Ensure the flag name here matches your Dashboard exactly</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> isFeatureEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> _configCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">GetValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"isMyFeatureEnabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Logger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">LogInformation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">$"ConfigCat Flag value: </span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token interpolation-string interpolation expression language-csharp">isFeatureEnabled</span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isFeatureEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"New Feature Logic Enabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Old Feature Active"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RedisCache</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token type-list class-name" style="color:rgb(255, 203, 107)">IConfigCatCache</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IDatabase</span><span class="token plain"> _database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">RedisCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> connectionString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> connection </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ConnectionMultiplexer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">connectionString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        _database </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">GetDatabase</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token return-type class-name punctuation" style="color:rgb(199, 146, 234)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">Get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> _database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">StringGet</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">Set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        _database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">StringSet</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">Task</span><span class="token return-type class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token return-type class-name punctuation" style="color:rgb(199, 146, 234)">?</span><span class="token return-type class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">GetAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">CancellationToken</span><span class="token plain"> cancellationToken </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> _database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">StringGetAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">Task</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">SetAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">CancellationToken</span><span class="token plain"> cancellationToken </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> _database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">StringSetAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>Production Note: AWS ElastiCache</div><div class="admonitionContent_BuS1"><p>In this tutorial, we use a public Redis Cloud instance for simplicity. In a real-world production environment, you should use <strong>AWS ElastiCache</strong>.</p><p>Using ElastiCache requires configuring your Lambda function to run inside a <strong>VPC</strong> (Virtual Private Cloud) and setting up Security Groups to allow traffic between the Lambda and the Redis Cluster.</p></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-bulb" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12h1m8-9v1m8 8h1M5.6 5.6l.7.7m12.1-.7-.7.7M9 16a5 5 0 1 1 6 0 3.5 3.5 0 0 0-1 3 2 2 0 0 1-4 0 3.5 3.5 0 0 0-1-3M9.7 17h4.6"></path></svg></span>Taking it a step further</div><div class="admonitionContent_BuS1"><p>Dedicate a separate application whose sole purpose is to keep your cache up to date. This can be a single Lambda function that initializes the ConfigCat client using <a href="https://configcat.com/docs/sdk-reference/dotnet/#manual-polling" target="_blank" rel="noopener noreferrer" class="">Manual Polling</a> and is configured to run on a schedule. When the interval is reached, the Lambda starts, calls <code>forceRefresh()</code> to trigger a cache update, and then shuts down.</p><p>Alternatively, you can initialize the client with Auto Polling and define an appropriate polling interval.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-deploying-to-aws">Step 4: Deploying to AWS<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#step-4-deploying-to-aws" class="hash-link" aria-label="Direct link to Step 4: Deploying to AWS" title="Direct link to Step 4: Deploying to AWS" translate="no">​</a></h3>
<p>Now that our code is ready, we need to push it to our AWS cloud. The .NET CLI makes this straightforward with the Amazon Lambda Tools.</p>
<ol>
<li class="">
<p><strong>Install the Lambda Tools</strong> (if you haven't installed it):</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet tool install </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain">g Amazon</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Lambda</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Tools</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>Deploy the Function:</strong>
Run the following command in your project folder. It will compile your code and upload it to AWS.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet lambda deploy-</span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> ConfigCatDemo</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>Test the Function:</strong>
Once deployed, you can invoke the function directly from the CLI to see the result immediately:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet lambda </span><span class="token function" style="color:rgb(130, 170, 255)">invoke-function</span><span class="token plain"> ConfigCatDemo </span><span class="token operator" style="color:rgb(137, 221, 255)">--</span><span class="token plain">payload </span><span class="token string" style="color:rgb(195, 232, 141)">"test"</span><br></div></code></pre></div></div>
<p>If your feature flag is turned <strong>ON</strong> in ConfigCat, you will see the payload response:
<code>New Feature Logic Enabled</code></p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-verifying-runtime-control">Step 5: Verifying Runtime Control<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#step-5-verifying-runtime-control" class="hash-link" aria-label="Direct link to Step 5: Verifying Runtime Control" title="Direct link to Step 5: Verifying Runtime Control" translate="no">​</a></h3>
<p>To see the "under the hood" details and confirm the Singleton pattern is working:</p>
<ol>
<li class="">Log in to your <strong>AWS Console</strong>.</li>
<li class="">Navigate to <strong>CloudWatch &gt; Logs &gt; Log management</strong>.</li>
<li class="">Click on <code>/aws/lambda/ConfigCatDemo</code>.</li>
<li class="">You will see the logs generated by our code confirming the flag value was retrieved successfully.</li>
</ol>
<img alt="Cloud Watch True" src="https://configcat.com/blog/assets/feature-flags-aws-lambda-dotnet/cloudwatch-true_192dpi.png" width="1366" height="518" decoding="async" loading="lazy" class="zoomable">
<p>Once deployed, you can verify that the feature flag works by toggling it in the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat Dashboard</a>.</p>
<p>To do this, you go to ConfigCat and toggle the flag <strong>OFF</strong>.</p>
<img alt="My Feature Flag Off" src="https://configcat.com/blog/assets/feature-flags-aws-lambda-dotnet/my-feature-flag-off_192dpi.png" width="1366" height="384" decoding="async" loading="lazy" class="zoomable">
<p><a href="https://aws.amazon.com/pm/lambda/" target="_blank" rel="noopener noreferrer" class="">AWS Lambda</a> doesn't listen for ConfigCat updates; it only checks when the function runs. So toggling the flag doesn't instantly change behavior. You need to wait for the cache to expire, then trigger a new execution.</p>
<p>After waiting 60+ seconds, invoke the function again:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">dotnet lambda </span><span class="token function" style="color:rgb(130, 170, 255)">invoke-function</span><span class="token plain"> ConfigCatDemo </span><span class="token operator" style="color:rgb(137, 221, 255)">--</span><span class="token plain">payload </span><span class="token string" style="color:rgb(195, 232, 141)">"test"</span><br></div></code></pre></div></div>
<p>Then, you will see the payload response: <code>"Old Feature Active"</code></p>
<p>And the CloudWatch logs show the flag evaluated as <code>false</code>:</p>
<img alt="Cloud Watch False" src="https://configcat.com/blog/assets/feature-flags-aws-lambda-dotnet/cloudwatch-false_192dpi.png" width="1366" height="518" decoding="async" loading="lazy" class="zoomable">
<p>That's runtime control in action; production behavior changed with zero deployments.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-6-implementing-progressive-delivery">Step 6: Implementing Progressive Delivery<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#step-6-implementing-progressive-delivery" class="hash-link" aria-label="Direct link to Step 6: Implementing Progressive Delivery" title="Direct link to Step 6: Implementing Progressive Delivery" translate="no">​</a></h3>
<p>Say you're launching a redesigned checkout experience for your e-commerce site. Pushing it to 100% of customers immediately is a gamble; a bug could tank your conversion rate.</p>
<p>This is where <a href="https://configcat.com/docs/glossary/#progressive-delivery" target="_blank" rel="noopener noreferrer" class=""><em>Progressive Delivery</em></a> shines. Start by serving the new flow to 10% of users. If checkout completion rates stay stable and error logs look clean, bump it to 30%, then 70%, then everyone. It's a controlled rollout, sometimes called a <a href="https://configcat.com/docs/glossary/#canary-testing" target="_blank" rel="noopener noreferrer" class=""><em>Canary Release</em></a>.</p>
<p>Traditional setups require custom load balancer logic or proxy configurations to perform canary releases. But, ConfigCat handles it with percentage-based <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer" class="">targeting rules</a> without code or infrastructure changes.</p>
<p>To do this:</p>
<ol>
<li class="">Go back to your ConfigCat Dashboard.</li>
<li class="">Find your <strong>isMyFeatureEnabled</strong> flag.</li>
<li class="">Instead of changing the main toggle, click on the <strong>+%</strong> button.</li>
<li class="">Set the rule to serve <strong>ON</strong> to <strong>10%</strong> of traffic and <strong>OFF</strong> to <strong>90%</strong>.</li>
</ol>
<img alt="My Feature Flag 10 percent" src="https://configcat.com/blog/assets/feature-flags-aws-lambda-dotnet/my-feature-flag-10percent_192dpi.png" width="1366" height="384" decoding="async" loading="lazy" class="zoomable">
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-progressive-delivery-works-well-with-serverless">Why Progressive Delivery Works Well with Serverless<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#why-progressive-delivery-works-well-with-serverless" class="hash-link" aria-label="Direct link to Why Progressive Delivery Works Well with Serverless" title="Direct link to Why Progressive Delivery Works Well with Serverless" translate="no">​</a></h4>
<p>Since Lambda functions are stateless, each invocation independently evaluates the 10% targeting rule through ConfigCat's SDK.</p>
<p>Here's what that looks like in practice:</p>
<ul>
<li class="">Watch CloudWatch logs as the feature rolls out</li>
<li class="">Errors show up? Only 10% of users are impacted</li>
<li class="">Everything stable? Bump the percentage (30% → 50% → 100%) from the dashboard</li>
</ul>
<p><strong>The microservices advantage:</strong></p>
<p>This decouples deployment timing across teams. If your checkout flow needs the new payment processing API, but that API isn't deployed yet. Ship your code with the flag off. When the payments team eventually deploys, you enable the flag remotely. No waiting, no coordinated release windows, no "we can't ship until Team B is ready" conversations.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="feature-flag-best-practices-for-microservices-and-serverless">Feature Flag Best Practices for Microservices and Serverless<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#feature-flag-best-practices-for-microservices-and-serverless" class="hash-link" aria-label="Direct link to Feature Flag Best Practices for Microservices and Serverless" title="Direct link to Feature Flag Best Practices for Microservices and Serverless" translate="no">​</a></h2>
<p>When using feature flags in distributed systems, keep the following practices in mind.</p>
<ol>
<li class="">
<p><strong>Always define fallback values:</strong> That fallback value in <code>GetValueAsync</code> determines what happens during ConfigCat outages. Pick the safest option by disabling the new feature. I've seen production incidents from missing defaults.</p>
</li>
<li class="">
<p><strong>Clean up old flags:</strong> Most teams use feature flags to manage and release a new feature. Once you've hit 100% rollout and the feature is stable, remove the flag from your code. The <a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">Zombie Flag Report</a> and the <a href="https://configcat.com/docs/advanced/code-references/overview/" target="_blank" rel="noopener noreferrer" class="">Code References tool</a> do a good job of helping you identify stale flags in your code before they become technical debt.</p>
</li>
<li class="">
<p><strong>Balance cache duration</strong> 60 seconds hits a good balance: flag changes propagate reasonably fast without excessive API calls inflating your Lambda execution costs. You can adjust this interval based on how quickly you need updates vs. what you're willing to pay.</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/feature-flags-aws-lambda-dotnet/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Feature flags are a powerful tool for managing releases in microservices and serverless architectures.</p>
<p>By combining AWS Lambda, Redis caching, and ConfigCat, teams can safely control application behavior without redeploying code.</p>
<p>This approach enables:</p>
<ul>
<li class="">safer deployments</li>
<li class="">progressive rollouts</li>
<li class="">instant rollback capabilities</li>
<li class="">better collaboration across teams</li>
</ul>
<p>Whether you're running microservices on Kubernetes or serverless workloads on AWS Lambda, feature flags provide a flexible way to release software with confidence.</p>
<p>Beyond .NET, ConfigCat provides a wide range of <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">SDKs</a> that work seamlessly with other AWS Lambda runtimes, including Node.js, Python, Go, and Java. To learn more, check out <a href="https://configcat.com/docs" target="_blank" rel="noopener noreferrer" class="">ConfigCat's official documentation</a>.</p>
<p>To get more posts like this and the latest updates, follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>microservice</category>
            <category>aws</category>
            <category>lambda</category>
            <category>.NET</category>
        </item>
        <item>
            <title><![CDATA[Feature Flag Best Practices: 7 Common Mistakes to Avoid]]></title>
            <link>https://configcat.com/blog/feature-flag-best-practices/</link>
            <guid>https://configcat.com/blog/feature-flag-best-practices/</guid>
            <pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Avoid the most common feature flag mistakes and learn feature flag best practices for naming conventions, stale flags, security, and proper release planning.]]></description>
            <content:encoded><![CDATA[<p>Feature flags (also called feature toggles) let development teams release features safely without redeploying code. They power gradual rollouts, A/B testing, and fast rollbacks when things go wrong.</p>
<p>But as systems grow, feature flags often become a source of hidden complexity. Flags pile up, naming breaks down, and unclear ownership leads to risky changes in production. What starts as a simple toggle system can quickly turn into long-term technical debt.</p>
<p>This guide walks through seven common feature flag mistakes and the best practices to avoid them, so your system stays clean, predictable, and safe to work with.</p>
<img alt="Feature Flag Best Practices - Top Mistakes to Avoid" src="https://configcat.com/blog/assets/feature-flag-best-practices/feature-flag-best-practices-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-feature-flag-best-practices-matter">Why Feature Flag Best Practices Matter<a href="https://configcat.com/blog/feature-flag-best-practices/#why-feature-flag-best-practices-matter" class="hash-link" aria-label="Direct link to Why Feature Flag Best Practices Matter" title="Direct link to Why Feature Flag Best Practices Matter" translate="no">​</a></h2>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer" class="">Feature flags</a> separate deployment from release. This means teams can ship code to production while keeping new functionality hidden until the right moment. Product managers, developers, and operations teams can decide when a feature becomes visible to users.</p>
<p>This approach supports several modern development practices:</p>
<ul>
<li class=""><strong>Gradual rollouts</strong>: expose a feature to 5% of users, then 25%, then 100%</li>
<li class=""><strong>Canary releases</strong>: test changes on a small cohort before full release</li>
<li class=""><strong>Kill switches</strong>: instantly disable a broken feature without a hotfix</li>
<li class=""><strong>A/B testing</strong>: compare feature variants across user segments</li>
<li class=""><strong>Trunk-based development</strong>: ship incomplete features safely behind a flag</li>
</ul>
<p>But when feature flags are used without clear rules, problems start to appear:</p>
<ul>
<li class="">unused flags clutter the codebase</li>
<li class="">unclear ownership of flags</li>
<li class="">confusing naming conventions</li>
<li class="">security risks in frontend implementations</li>
</ul>
<p>A few consistent practices keep feature flag systems clean, predictable, and easy to maintain.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-leaving-old-or-stale-feature-flags-in-the-codebase">1. Leaving Old or Stale Feature Flags in the Codebase<a href="https://configcat.com/blog/feature-flag-best-practices/#1-leaving-old-or-stale-feature-flags-in-the-codebase" class="hash-link" aria-label="Direct link to 1. Leaving Old or Stale Feature Flags in the Codebase" title="Direct link to 1. Leaving Old or Stale Feature Flags in the Codebase" translate="no">​</a></h2>
<p>A feature is released. Everything works. The flag stays. This is one of the most common patterns teams run into.</p>
<p>Over time, these unused flags pile up and create what many engineers refer to as flag debt or <a href="https://configcat.com/docs/faq/#what-are-zombie-stale-flags" target="_blank" rel="noopener noreferrer" class="">zombie flags</a>. A developer reading the code cannot easily tell whether a flag still has a purpose.</p>
<p>Stale flags cause real problems:</p>
<ul>
<li class="">Code becomes harder to read and reason about</li>
<li class="">Conditional branches remain in production for features that are 100% rolled out</li>
<li class="">Accidental changes to an old flag value can affect live behavior in unexpected ways</li>
<li class="">In mobile apps, a flag may still be evaluated by users on older versions who haven't updated</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-works-in-practice">What works in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-works-in-practice" class="hash-link" aria-label="Direct link to What works in practice" title="Direct link to What works in practice" translate="no">​</a></h3>
<p>Teams that keep feature flags under control usually treat cleanup as a recurring task, not a one-time effort.</p>
<p>One approach that works well is scheduling regular cleanup sessions. For example, some teams run a quarterly "cleanup day", where removing unused flags is a standing agenda item. This aligns well with release cycles, especially in environments where updates take time to reach all users.</p>
<p>Another pattern is to introduce limits. Some teams define a feature flag budget per team. If the number of active flags exceeds that limit, the build or deployment pipeline fails. This forces teams to review and remove unused flags before adding new ones.</p>
<p>There are also teams that categorize flags from the start:</p>
<ul>
<li class="">short-term flags used during rollout</li>
<li class="">medium or long-term flags used for gradual control</li>
<li class="">permanent flags used as kill switches</li>
</ul>
<p>In this model, removing short-term flags becomes part of the release process. When a feature is fully rolled out, a cleanup task is created alongside the original implementation work.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-common-challenge">A common challenge<a href="https://configcat.com/blog/feature-flag-best-practices/#a-common-challenge" class="hash-link" aria-label="Direct link to A common challenge" title="Direct link to A common challenge" translate="no">​</a></h3>
<p>One difficulty that often comes up is knowing when it is safe to remove a flag. Even if a feature has been released, older versions of an application may still be in use. This is especially common in mobile apps, where users do not always update immediately.</p>
<p>In these cases, a flag may still be evaluated by older versions in the wild, even if it appears unused in the current codebase.</p>
<p>Tools like <a href="https://configcat.com/docs/zombie-flags/#managing-zombie-flags-in-configcat" target="_blank" rel="noopener noreferrer" class="">ConfigCat's Zombie Feature Flags Report</a> can highlight flags that haven't changed recently, but teams often need additional signals (such as whether a flag is still being evaluated) before removing with confidence.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-reusing-feature-flags-instead-of-creating-new-ones">2. Reusing Feature Flags Instead of Creating New Ones<a href="https://configcat.com/blog/feature-flag-best-practices/#2-reusing-feature-flags-instead-of-creating-new-ones" class="hash-link" aria-label="Direct link to 2. Reusing Feature Flags Instead of Creating New Ones" title="Direct link to 2. Reusing Feature Flags Instead of Creating New Ones" translate="no">​</a></h2>
<p>Reusing a feature flag may feel efficient. In reality, it creates hidden complexity. A flag designed for one feature gets repurposed for another. Its name no longer reflects its behavior, and debugging becomes harder.</p>
<p>In extreme cases, this can lead to serious issues. There are well-known incidents where old flag logic was unintentionally reused, causing unexpected system behavior.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-works-in-practice-1">What works in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-works-in-practice-1" class="hash-link" aria-label="Direct link to What works in practice" title="Direct link to What works in practice" translate="no">​</a></h3>
<p>Teams that avoid this follow a strict rule: <strong>a flag is tied to one purpose only</strong>. If the purpose changes, a new flag is created.</p>
<p>Naming conventions play an important role here. A clear, descriptive name makes it easier to understand what a flag does without digging into the code.</p>
<p>A good feature flag name should reflect:</p>
<ul>
<li class="">a feature area</li>
<li class="">the functionality being controlled</li>
<li class="">optionally, the team responsible</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Check out our <a href="https://configcat.com/blog/feature-flag-naming-conventions/" target="_blank" rel="noopener noreferrer" class="">Quick Guide to Feature Flag Naming Conventions</a> article to learn more.</p></div></div>
<p>Pattern: <code>{team}_{area}_{behavior}</code>:</p>
<ul>
<li class=""><code>payments_checkout_newPaymentFlow</code></li>
<li class=""><code>search_results_rankingAlgorithmV2</code></li>
<li class=""><code>onboarding_signup_emailVerificationRequired</code></li>
</ul>
<p>Avoid vague names:</p>
<ul>
<li class=""><code>newFeature</code>   // What feature?</li>
<li class=""><code>betaEnabled</code> // Beta of what?</li>
<li class=""><code>enableV2</code>    // V2 of which thing?</li>
</ul>
<p>Note: Avoid prefixing flags with <code>enable</code> or <code>disable</code>; it's redundant since all flags enable or disable something, and it adds noise without meaning.</p>
<p>Common naming styles include camelCase, PascalCase, lower_case, UPPER_CASE, and kebab-case. The specific format matters less than consistency. A predictable structure makes flags understandable across the entire team.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-using-feature-flags-without-backend-protection">3. Using Feature Flags Without Backend Protection<a href="https://configcat.com/blog/feature-flag-best-practices/#3-using-feature-flags-without-backend-protection" class="hash-link" aria-label="Direct link to 3. Using Feature Flags Without Backend Protection" title="Direct link to 3. Using Feature Flags Without Backend Protection" translate="no">​</a></h2>
<p>Feature flags are often used to control interface elements such as buttons, menu items, or entire pages. However, relying solely on frontend feature flags can introduce security and reliability risks. Because frontend flags are delivered to the browser when the application loads, their values can be inspected, modified, or bypassed entirely. A user does not need to see a button to call the API endpoint behind it.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-scenario">Example Scenario<a href="https://configcat.com/blog/feature-flag-best-practices/#example-scenario" class="hash-link" aria-label="Direct link to Example Scenario" title="Direct link to Example Scenario" translate="no">​</a></h3>
<p>A new <em>Export Data</em> button is hidden behind a feature flag. The button doesn't render, but the <code>/api/data/export</code> endpoint has no flag check on the server. Anyone who knows the endpoint exists (or who previously had access and bookmarked it) can call it directly.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="best-practice">Best Practice<a href="https://configcat.com/blog/feature-flag-best-practices/#best-practice" class="hash-link" aria-label="Direct link to Best Practice" title="Direct link to Best Practice" translate="no">​</a></h3>
<p>Use two layers of protection:</p>
<ol>
<li class="">Frontend flag: controls whether the UI element appears</li>
<li class="">Backend flag: controls access to the underlying logic</li>
</ol>
<p>With this approach, even if the interface becomes visible prematurely, the backend still prevents unintended access. Whenever possible, evaluating feature flags on the server side offers stronger protection.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Learn the difference between <a href="https://configcat.com/blog/feature-flag-naming-conventions/" target="_blank" rel="noopener noreferrer" class="">Frontend Feature Flags vs Backend Feature Flags</a>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-not-planning-feature-rollouts-properly">4. Not Planning Feature Rollouts Properly<a href="https://configcat.com/blog/feature-flag-best-practices/#4-not-planning-feature-rollouts-properly" class="hash-link" aria-label="Direct link to 4. Not Planning Feature Rollouts Properly" title="Direct link to 4. Not Planning Feature Rollouts Properly" translate="no">​</a></h2>
<p>Feature flags make gradual rollouts possible, but they do not replace release planning. A feature can still be enabled for all users at once, which removes the main advantage of using feature flags.</p>
<p>Without a staged rollout, you lose the ability to catch issues early. A bug that only appears under real production load hits all your users at once, not 5% of them.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-works-in-practice-2">What works in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-works-in-practice-2" class="hash-link" aria-label="Direct link to What works in practice" title="Direct link to What works in practice" translate="no">​</a></h3>
<p>Define rollout stages before you flip the first switch. A typical staged rollout:</p>
<table><thead><tr><th>Stage</th><th>Audience</th><th>Duration</th><th>What to watch</th></tr></thead><tbody><tr><td>Internal</td><td>Employees only</td><td>1–2 days</td><td>Basic functionality, crashes</td></tr><tr><td>Canary</td><td>1–5% of users</td><td>3–5 days</td><td>Error rates, performance, conversion</td></tr><tr><td>Partial</td><td>10–25% of users</td><td>3–7 days</td><td>User behavior, support tickets</td></tr><tr><td>Full</td><td>100%</td><td>—</td><td>Monitor for regressions</td></tr></tbody></table>
<p>Monitoring without baselines is guesswork. Before enabling a flag for any users, establish what normal looks like: error rates, p95/p99 latency, and key conversion metrics. Then watch for deviations at each stage.</p>
<p>At each stage, observe:</p>
<ul>
<li class="">Error rates: compared to the control groups</li>
<li class="">Performance: latency and throughput changes</li>
<li class="">User behavior: conversion, engagement, support volume</li>
</ul>
<p>Define explicit thresholds for rollback before you start. <em>"If error rate increases by more than 0.5% compared to the control group, roll back"</em> is a decision you can make calmly in advance. It's much harder to make a clear decision in the middle of an incident.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-storing-sensitive-data-in-feature-flags">5. Storing Sensitive Data in Feature Flags<a href="https://configcat.com/blog/feature-flag-best-practices/#5-storing-sensitive-data-in-feature-flags" class="hash-link" aria-label="Direct link to 5. Storing Sensitive Data in Feature Flags" title="Direct link to 5. Storing Sensitive Data in Feature Flags" translate="no">​</a></h2>
<p>Feature flags should not contain sensitive data such as connection strings, API keys, or credentials.</p>
<p>The reason is simple: feature flags are not secrets managers. A frontend flag is delivered to the browser at page load and is readable by anyone with DevTools open. But even backend flag configurations lack the access controls, audit logging, and rotation mechanisms that credentials require.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-fix-it">How to fix it<a href="https://configcat.com/blog/feature-flag-best-practices/#how-to-fix-it" class="hash-link" aria-label="Direct link to How to fix it" title="Direct link to How to fix it" translate="no">​</a></h3>
<p>Use dedicated secrets management infrastructure for anything sensitive:</p>
<table><thead><tr><th>Sensitive data type</th><th>Use instead</th></tr></thead><tbody><tr><td>API keys</td><td><a href="https://aws.amazon.com/secrets-manager/" target="_blank" rel="noopener noreferrer" class="">AWS Secrets Manager</a>, <a href="https://www.hashicorp.com/en/products/vault" target="_blank" rel="noopener noreferrer" class="">HashiCorp Vault</a>, <a href="https://azure.microsoft.com/en-us/products/key-vault" target="_blank" rel="noopener noreferrer" class="">Azure Key Vault</a></td></tr><tr><td>Database credentials</td><td>Same as above, or environment variables in CI/CD</td></tr><tr><td>OAuth client secrets</td><td>Secrets manager, never source control or flags</td></tr><tr><td>Encryption keys</td><td>KMS (AWS, GCP, Azure)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-overloading-feature-flags-with-complex-logic">6. Overloading Feature Flags with Complex Logic<a href="https://configcat.com/blog/feature-flag-best-practices/#6-overloading-feature-flags-with-complex-logic" class="hash-link" aria-label="Direct link to 6. Overloading Feature Flags with Complex Logic" title="Direct link to 6. Overloading Feature Flags with Complex Logic" translate="no">​</a></h2>
<p>Feature flags should control a single, well-defined behavior. When a single flag controls multiple features or contains complex logic, it quickly becomes difficult to understand, test, and maintain.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-works-in-practice-3">What works in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-works-in-practice-3" class="hash-link" aria-label="Direct link to What works in practice" title="Direct link to What works in practice" translate="no">​</a></h3>
<p>Teams that avoid this keep flags focused and predictable. What starts as a simple toggle can easily turn into a mini decision engine embedded in your code.</p>
<p>This often happens when teams try to reduce the number of flags by grouping too much behind one. Instead of simplifying things, it creates hidden complexity.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-this-looks-like-in-practice">What this looks like in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-this-looks-like-in-practice" class="hash-link" aria-label="Direct link to What this looks like in practice" title="Direct link to What this looks like in practice" translate="no">​</a></h3>
<p>You might see flags that:</p>
<ul>
<li class="">control multiple unrelated behaviors</li>
<li class="">include nested conditions (user segment + region + plan + environment)</li>
<li class="">store structured data like JSON instead of a simple value</li>
<li class="">act differently depending on the context that is not immediately obvious</li>
</ul>
<p>At that point, understanding what the flag actually does requires reading multiple parts of the codebase.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-common-side-effect">A common side effect<a href="https://configcat.com/blog/feature-flag-best-practices/#a-common-side-effect" class="hash-link" aria-label="Direct link to A common side effect" title="Direct link to A common side effect" translate="no">​</a></h3>
<p>Overloaded flags often lead to unexpected interactions. A small change in targeting or rollout rules can affect multiple parts of the system at once. This makes debugging harder and increases the risk of unintended behavior in production.</p>
<p>Keeping flags small and focused reduces the risk significantly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-not-having-a-flag-ownership-model">7. Not Having a Flag Ownership Model<a href="https://configcat.com/blog/feature-flag-best-practices/#7-not-having-a-flag-ownership-model" class="hash-link" aria-label="Direct link to 7. Not Having a Flag Ownership Model" title="Direct link to 7. Not Having a Flag Ownership Model" translate="no">​</a></h2>
<p>Most articles on feature flags focus on the flags themselves. This one is about the system around them, and it's where many teams quietly fail.</p>
<p>As teams and flag counts grow, questions that were easy to answer in a small codebase become difficult: <em>Who created this flag?</em> <em>Is it still needed?</em>  <em>Who can change it? What happens if it's toggled in production right now?</em></p>
<p>Without explicit ownership, flags become a shared global state that nobody feels fully responsible for.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-this-looks-like-in-practice-1">What this looks like in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-this-looks-like-in-practice-1" class="hash-link" aria-label="Direct link to What this looks like in practice" title="Direct link to What this looks like in practice" translate="no">​</a></h3>
<ul>
<li class="">A flag exists, but nobody knows if it's safe to delete</li>
<li class="">A flag is changed in production by one team, breaking behavior owned by another</li>
<li class="">Flags are created without documentation, and six months later, the original context is gone</li>
<li class="">An audit question like <em>"who changed this flag and when?"</em> has no clear answer</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-works-in-practice-4">What works in practice<a href="https://configcat.com/blog/feature-flag-best-practices/#what-works-in-practice-4" class="hash-link" aria-label="Direct link to What works in practice" title="Direct link to What works in practice" translate="no">​</a></h3>
<ul>
<li class=""><strong>Assign ownership explicitly:</strong> every flag should have a named owner (a team, a squad, or a specific person) and that ownership should be visible in the flag management tool, not just in a document somewhere</li>
<li class=""><strong>Document at creation time, not after:</strong> a flag's description should include: what it does, why it exists, when it can be deleted, and what the safe default value is if the flag evaluation fails. This takes two minutes to write when the context is fresh and hours to reconstruct later</li>
<li class=""><strong>Require an audit log:</strong> for production systems, every flag change should be traceable: who made the change, from what value to what value, and when. This is essential for incident response</li>
<li class=""><strong>Include flags in incident reviews:</strong> when a production incident involves a flag change, review whether the ownership and change process worked as intended. Flags that caused the incidents are often flags that lacked clear ownership</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-to-bring-in-a-feature-flag-management-tool">When to Bring in a Feature Flag Management Tool<a href="https://configcat.com/blog/feature-flag-best-practices/#when-to-bring-in-a-feature-flag-management-tool" class="hash-link" aria-label="Direct link to When to Bring in a Feature Flag Management Tool" title="Direct link to When to Bring in a Feature Flag Management Tool" translate="no">​</a></h2>
<p>As the number of flags grows, managing them manually (in config files, environment variables, or a homegrown database table) becomes a significant operational burden. A dedicated tool provides the infrastructure that makes the practices above sustainable at scale.</p>
<p>What to look for when evaluating a tool:</p>
<ul>
<li class=""><strong>Audit log:</strong> who changed what flag, when, and to what value</li>
<li class=""><strong>Targeting and segmentation:</strong> roll out to specific users, regions, or cohorts</li>
<li class=""><strong>SDK support:</strong> server-side SDKs are essential for backend enforcement</li>
<li class=""><strong>Lifecycle management:</strong> surfaces stale or unused flags before they become technical debt</li>
</ul>
<p>Without tooling, most of the practices in this article require manual discipline that doesn't scale. Tooling makes the discipline structural.</p>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> is one option worth evaluating, particularly for teams that want straightforward flag management without significant infrastructure overhead. It provides <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">SDK support across major languages</a>, a clean targeting interface, a <a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">Zombie Flags Report</a> for stale flag detections, and full audit logging.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="to-sum-it-up">To Sum It Up<a href="https://configcat.com/blog/feature-flag-best-practices/#to-sum-it-up" class="hash-link" aria-label="Direct link to To Sum It Up" title="Direct link to To Sum It Up" translate="no">​</a></h2>
<p>Feature flags make it easier to release features gradually, test changes in production, and respond quickly when something goes wrong. At the same time, they introduce a layer that needs to be maintained.</p>
<p>Most issues with feature flags come from how they are used. Flags remain in the system longer than intended, get reused without a clear meaning, or are introduced without a plan for how they will be removed.</p>
<p>With the best practices covered, managing feature flags doesn't have to be a headache. Keep them short-lived, keep them named clearly, keep sensitive data out of them, and clean them up when the job is done.</p>
<p>If you want to learn more about feature flags or stay up to date with all the latest news, follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a> to learn more.</p>]]></content:encoded>
            <category>sensitive text comparators</category>
            <category>software release best practices</category>
            <category>unused feature flags</category>
        </item>
        <item>
            <title><![CDATA[Canary Releases with Feature Flags: How to Roll Out from 1% to 100%]]></title>
            <link>https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/</link>
            <guid>https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/</guid>
            <pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to roll out features from 1% to 100% using canary releases and feature flags. Includes real rollout steps, monitoring, and safe rollback strategies.]]></description>
            <content:encoded><![CDATA[<p>When shipping new features, releasing them to all users at once can be risky. Even small bugs can affect thousands of users immediately. That's why modern teams rely on canary releases and feature flags to roll out changes gradually, monitor real-world performance, and reduce the risk of failure.</p>
<p>In this guide, you'll learn:</p>
<ul>
<li class="">What a canary release is</li>
<li class="">How it works with <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer" class="">feature flags</a></li>
<li class="">A step-by-step rollout strategy using <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a></li>
<li class="">Best practices and common mistakes to avoid</li>
</ul>
<img alt="Canary release cover cover" src="https://configcat.com/blog/assets/canary-release/canary-release-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-a-canary-release">What Is a Canary Release?<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#what-is-a-canary-release" class="hash-link" aria-label="Direct link to What Is a Canary Release?" title="Direct link to What Is a Canary Release?" translate="no">​</a></h2>
<p>A canary release (also called a <em>canary deployment)</em> is a strategy where a new feature is introduced to a small subset of users before being rolled out to everyone. Instead of releasing a feature globally, the rollout happens in controlled stages.</p>
<p>Example rollout strategy:</p>
<p><code>Team members → Beta users → 1% of users → 5% of users → All users</code></p>
<p>This incremental approach helps teams:</p>
<ul>
<li class="">Limit the impact of potential issues</li>
<li class="">Test features with real users</li>
<li class="">Gather early feedback</li>
<li class="">Roll back quickly if something goes wrong</li>
</ul>
<p>Feature flags make this strategy even easier because they allow teams to control feature visibility without redeploying code. If you're new to this concept, our guide on feature flags and how they work explains the fundamentals and common use cases.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-is-it-called-a-canary-release">Why Is It Called a Canary Release?<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#why-is-it-called-a-canary-release" class="hash-link" aria-label="Direct link to Why Is It Called a Canary Release?" title="Direct link to Why Is It Called a Canary Release?" translate="no">​</a></h3>
<p>The term comes from coal mining, where miners used canaries to detect toxic gases. If the canary was affected, it warned miners of danger.</p>
<p>In software, early users act as the "canary", helping detect issues before a full rollout.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-should-you-use-a-canary-release">When Should You Use a Canary Release?<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#when-should-you-use-a-canary-release" class="hash-link" aria-label="Direct link to When Should You Use a Canary Release?" title="Direct link to When Should You Use a Canary Release?" translate="no">​</a></h2>
<p>Canary releases are especially useful when:</p>
<ul>
<li class="">You're shipping high-risk or critical features</li>
<li class="">You want to test changes in a real production environment</li>
<li class="">Performance or scalability is a concern</li>
<li class="">You have a large user base and want to reduce rollout risk</li>
</ul>
<p>For example, in <a href="https://configcat.com/blog/2023/10/20/Feature-flag-implementation-microservices-architecture/" target="_blank" rel="noopener noreferrer" class="">microservices architecture</a>, canary releases help isolate failures without impacting the entire system.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benefits-of-canary-releases">Benefits of Canary Releases<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#benefits-of-canary-releases" class="hash-link" aria-label="Direct link to Benefits of Canary Releases" title="Direct link to Benefits of Canary Releases" translate="no">​</a></h2>
<p>A well-executed canary rollout helps teams:</p>
<ul>
<li class="">Catch bugs in real-world conditions</li>
<li class="">Monitor performance under gradual load</li>
<li class="">Ship features with more confidence</li>
<li class="">Roll back quickly if issues appear</li>
<li class="">Build confidence before a full rollout</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="challenges-to-be-aware-of">Challenges to Be Aware Of<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#challenges-to-be-aware-of" class="hash-link" aria-label="Direct link to Challenges to Be Aware Of" title="Direct link to Challenges to Be Aware Of" translate="no">​</a></h2>
<p>Canary releases aren't without tradeoffs. Depending on your setup, you may need to handle:</p>
<ul>
<li class="">Multiple versions of your application</li>
<li class="">Increased infrastructure complexity</li>
<li class="">Database compatibility between versions</li>
<li class="">Additional monitoring requirements</li>
</ul>
<p>This is why many teams rely on <a href="https://configcat.com/feature-flagging-tools/" target="_blank" rel="noopener noreferrer" class="">feature flag platforms</a> to simplify rollout logic.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="canary-release-vs-ab-testing">Canary Release vs A/B Testing<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#canary-release-vs-ab-testing" class="hash-link" aria-label="Direct link to Canary Release vs A/B Testing" title="Direct link to Canary Release vs A/B Testing" translate="no">​</a></h2>
<p>These concepts are often confused but serve different purposes:</p>
<ul>
<li class=""><strong>Canary releases:</strong> detect bugs, regressions, and performance issues</li>
<li class=""><strong>A/B testing:</strong> test product ideas and user behavior</li>
</ul>
<p>Canary rollouts typically complete in minutes or hours, while A/B tests may run for days to reach statistical significance.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-feature-flags-simplify-canary-releases">How Feature Flags Simplify Canary Releases<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#how-feature-flags-simplify-canary-releases" class="hash-link" aria-label="Direct link to How Feature Flags Simplify Canary Releases" title="Direct link to How Feature Flags Simplify Canary Releases" translate="no">​</a></h2>
<p>Feature flags (also called <em>feature toggles</em>) give you direct control over how features are exposed without redeploying your application.</p>
<p>Instead of relying on infrastructure-heavy solutions like traffic routing or load balancers, you can manage rollouts directly in your code and dashboard.</p>
<p>With feature flags, you can:</p>
<ul>
<li class="">Release a feature to a specific group of users</li>
<li class="">Roll out changes gradually using percentages</li>
<li class="">Turn features off instantly if needed</li>
</ul>
<p>This approach fits into <a href="https://configcat.com/blog/2022/01/14/progressive-delivery/" target="_blank" rel="noopener noreferrer" class="">progressive delivery</a>, where features are released in controlled steps instead of all at once.</p>
<p>Platforms like ConfigCat make this even easier by letting you define targeting rules and rollout percentages without modifying your codebase.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-choose-canary-users">How to Choose Canary Users<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#how-to-choose-canary-users" class="hash-link" aria-label="Direct link to How to Choose Canary Users" title="Direct link to How to Choose Canary Users" translate="no">​</a></h2>
<p>Before starting a rollout, decide who should see the feature first.</p>
<p>Common strategies include:</p>
<ul>
<li class="">Internal team members (developers, QA)</li>
<li class="">Beta testers or early adopters</li>
<li class="">A random percentage of users</li>
<li class="">Specific regions or countries</li>
<li class="">Low-risk or non-critical users</li>
</ul>
<p>Choosing the right users helps reduce risk and gather meaningful feedback early.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-simple-canary-release-with-configcat">A Simple Canary Release with ConfigCat<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#a-simple-canary-release-with-configcat" class="hash-link" aria-label="Direct link to A Simple Canary Release with ConfigCat" title="Direct link to A Simple Canary Release with ConfigCat" translate="no">​</a></h2>
<p>Let's look at how a basic rollout might work in practice.</p>
<p>In this example, we assume you've already:</p>
<ul>
<li class="">Logged into the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a></li>
<li class="">Created a feature flag</li>
<li class="">Integrated the <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">ConfigCat SDK</a> into your application</li>
</ul>
<p>Our feature flag will be called:</p>
<p><code>facebook_sharing_enabled</code></p>
<p>Initially, the feature is turned off for everyone.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-start-with-the-feature-disabled-unreleased-state">Step 1: Start with the Feature Disabled (Unreleased State)<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-1-start-with-the-feature-disabled-unreleased-state" class="hash-link" aria-label="Direct link to Step 1: Start with the Feature Disabled (Unreleased State)" title="Direct link to Step 1: Start with the Feature Disabled (Unreleased State)" translate="no">​</a></h3>
<p>At this point the feature flag already exists, but it isn't serving the feature to everyone.</p>
<p>In the ConfigCat dashboard, the flag is simply set to <code>OFF</code>, which means every user will receive the default value and the feature remains hidden.</p>
<img alt="Unreleased state" src="https://configcat.com/blog/assets/canary-release/1-unreleased_192dpi.png" width="1247" height="225" decoding="async" loading="lazy" class="zoomable">
<p>This is usually how a rollout begins. The code for the feature can already be deployed in production, while the flag keeps the functionality disabled until you're ready to start exposing it to users.</p>
<p>In other words, the application contains the new functionality, but the feature flag ensures that users won't see it yet.</p>
<p>A simple example might look like this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">if (configCatClient.getValue("facebook_sharing_enabled", false)) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  showFacebookShareButton();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>Since the flag is currently <code>OFF</code> for everyone, the Facebook sharing button will not appear for any users.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-release-to-internal-team-members">Step 2: Release to Internal Team Members<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-2-release-to-internal-team-members" class="hash-link" aria-label="Direct link to Step 2: Release to Internal Team Members" title="Direct link to Step 2: Release to Internal Team Members" translate="no">​</a></h3>
<p>The next step is to enable the feature only for internal users. Before rolling out a new feature to real users, many teams first expose it to developers, testers, or product managers inside the company. This makes it possible to test the feature in a real production environment and quickly gather feedback.</p>
<p>In this example, the feature flag is enabled only for users whose email contains <code>@mycompany.com</code>.</p>
<img alt="Releasing to team" src="https://configcat.com/blog/assets/canary-release/2-releases-to-my-team_192dpi.png" width="1247" height="416" decoding="async" loading="lazy" class="zoomable">
<p>Everyone else will still receive the <code>OFF</code> value, so the feature remains hidden from external users.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-expand-to-trusted-users-beta-group">Step 3: Expand to Trusted Users (Beta Group)<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-3-expand-to-trusted-users-beta-group" class="hash-link" aria-label="Direct link to Step 3: Expand to Trusted Users (Beta Group)" title="Direct link to Step 3: Expand to Trusted Users (Beta Group)" translate="no">​</a></h3>
<p>Next, you can expand the rollout to a slightly larger group. In addition to internal team members, many teams include a small group of trusted users such as friends, beta testers, or early adopters. These users can provide valuable feedback before the feature becomes available to everyone.</p>
<p>In this example, the feature is enabled for users whose email contains <code>@mycompany.com</code> or <code>@friends.com</code>.</p>
<img alt="Releasing to team and friends" src="https://configcat.com/blog/assets/canary-release/3-released-to-my-team-and-friends_192dpi.png" width="1247" height="417" decoding="async" loading="lazy" class="zoomable">
<p>Everyone else will still receive the <code>OFF</code> value, so the feature remains hidden from the wider audience. This step helps gather feedback from real users in a controlled way before moving to a broader rollout.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-release-to-1-of-users---but-no-sensitive-users">Step 4: Release to 1% of Users - But No Sensitive Users<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-4-release-to-1-of-users---but-no-sensitive-users" class="hash-link" aria-label="Direct link to Step 4: Release to 1% of Users - But No Sensitive Users" title="Direct link to Step 4: Release to 1% of Users - But No Sensitive Users" translate="no">​</a></h3>
<p>If more feedback is needed, the next step is to expose the feature to a small percentage of users. Instead of enabling the feature for everyone at once, you can gradually roll it out to a small portion of your user base and observe how it behaves in production. This approach is commonly known as canary release.</p>
<p>In this example, the feature is enabled for 1% of users, while the remaining 99% still receive the <code>OFF</code> value.</p>
<img alt="Releasing to 1%" src="https://configcat.com/blog/assets/canary-release/4-released-to-1_-but-no-sensistive-users_192dpi.png" width="1232" height="587" decoding="async" loading="lazy" class="zoomable">
<p>At the same time, it's often a good idea to exclude certain users from early rollouts. These might include high-value customers, sensitive markets, or users who rely heavily on the stability of your product.</p>
<p>In the screenshot above, users from the United States are treated as sensitive users and are explicitly excluded from the rollout.</p>
<p>This way you can safely collect feedback from a small portion of real users while reducing the risk of impacting your most sensitive user groups.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-increase-to-5-of-users---but-no-sensitive-users">Step 5: Increase to 5% of Users - But No Sensitive Users<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-5-increase-to-5-of-users---but-no-sensitive-users" class="hash-link" aria-label="Direct link to Step 5: Increase to 5% of Users - But No Sensitive Users" title="Direct link to Step 5: Increase to 5% of Users - But No Sensitive Users" translate="no">​</a></h3>
<p>Once the feature works well for internal users and early testers, the rollout can be expanded further.</p>
<p>In this step, the feature is enabled for 5% of users, while sensitive users are still excluded. This gradually increases exposure while keeping the risk under control.</p>
<img alt="Releasing to 5%" src="https://configcat.com/blog/assets/canary-release/5-released-to-5_-but-no-sensistive-users_192dpi.png" width="1232" height="587" decoding="async" loading="lazy" class="zoomable">
<p>At this point, the feature is available to team members, friends, and a small portion of the general user base, while the remaining users still receive the <code>OFF</code> value.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-6-release-to-everyone-except-sensitive-users">Step 6: Release to Everyone Except Sensitive Users<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-6-release-to-everyone-except-sensitive-users" class="hash-link" aria-label="Direct link to Step 6: Release to Everyone Except Sensitive Users" title="Direct link to Step 6: Release to Everyone Except Sensitive Users" translate="no">​</a></h3>
<p>At this stage, the feature has already been tested with internal users, trusted testers, and a small percentage of the user base. The feedback collected during those steps should give enough confidence to expand the rollout further.</p>
<p>Now the feature can be enabled for all users except the sensitive group.</p>
<img alt="Releasing to everyone but sensitive users" src="https://configcat.com/blog/assets/canary-release/6-released-to-everyone-except-sensitive-users_192dpi.png" width="1247" height="421" decoding="async" loading="lazy" class="zoomable">
<p>In this example, users from the United States are still excluded from the rollout, while everyone else receives the ON value.</p>
<p>This step exposes the feature to almost the entire user base while still protecting the most sensitive users until the rollout is fully validated.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-7-release-to-everyone">Step 7: Release to Everyone<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#step-7-release-to-everyone" class="hash-link" aria-label="Direct link to Step 7: Release to Everyone" title="Direct link to Step 7: Release to Everyone" translate="no">​</a></h3>
<p>If everything looks stable - bugs have been fixed, the UI behaves as expected, and feedback from early users is positive - the feature can finally be released to the entire user base, including previously excluded sensitive users.</p>
<img alt="Releasing to everyone" src="https://configcat.com/blog/assets/canary-release/7-released-to-everyone_192dpi.png" width="1247" height="230" decoding="async" loading="lazy" class="zoomable">
<p>At this point, the feature flag simply serves the ON value to all users, completing the rollout.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-monitor-during-a-canary-release">What to Monitor During a Canary Release<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#what-to-monitor-during-a-canary-release" class="hash-link" aria-label="Direct link to What to Monitor During a Canary Release" title="Direct link to What to Monitor During a Canary Release" translate="no">​</a></h2>
<p>Monitoring is what makes canary releases effective. Without it, you're just rolling out blindly.</p>
<p>Focus on core system metrics first:</p>
<ul>
<li class="">Error rates, to catch failures early</li>
<li class="">Latency and performance, to keep the app responsive</li>
<li class="">System load, especially if the feature adds overhead</li>
</ul>
<p>At the same time, watch how users respond:</p>
<ul>
<li class="">User behavior, such as drop-offs or unusual patterns</li>
<li class="">Conversion metrics, to measure real impact</li>
</ul>
<p>If anything looks wrong, feature flags act as a kill switch, letting you disable the feature instantly without redeploying.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="best-practices-for-canary-releases">Best Practices for Canary Releases<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#best-practices-for-canary-releases" class="hash-link" aria-label="Direct link to Best Practices for Canary Releases" title="Direct link to Best Practices for Canary Releases" translate="no">​</a></h2>
<p>A safe rollout is gradual and controlled. Start small and expand only when confident.</p>
<ul>
<li class="">Begin with internal users</li>
<li class="">Roll out step by step (1% → 5% → 25% → 100%)</li>
<li class="">Monitor metrics continuously</li>
</ul>
<p>To reduce risk:</p>
<ul>
<li class="">Exclude sensitive users early</li>
<li class="">Use feature flags for instant rollback</li>
</ul>
<p>After rollout, remove <a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">unused flags</a>. Following <a href="https://configcat.com/blog/feature-flag-naming-conventions/" target="_blank" rel="noopener noreferrer" class="">feature flag naming conventions</a> can also help keep things organized.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="common-canary-release-mistakes">Common Canary Release Mistakes<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#common-canary-release-mistakes" class="hash-link" aria-label="Direct link to Common Canary Release Mistakes" title="Direct link to Common Canary Release Mistakes" translate="no">​</a></h2>
<p>Even with a solid strategy, certain mistakes can reduce effectiveness of a canary release.</p>
<p>Common mistakes include:</p>
<ul>
<li class="">Rolling out too quickly</li>
<li class="">Not monitoring key metrics</li>
<li class="">Including sensitive users too early</li>
</ul>
<p>Over time, teams may also run into issues like:</p>
<ul>
<li class="">Leaving old feature flags in the codebase</li>
<li class="">Using canary releases as A/B tests instead of a risk-reduction strategy</li>
</ul>
<p>Keeping these mistakes in mind helps you maintain a safer, more controlled release process while getting the full benefits of canary deployments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/how-to-implement-a-canary-release-with-feature-flags/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Gradual rollouts help teams release new features with confidence. By starting with internal users, expanding to trusted testers, and slowly increasing the percentage of affected users, teams can monitor performance and catch issues early.</p>
<p>This type of canary release strategy reduces risk compared to releasing a feature to everyone at once.</p>
<p>Feature flag tools like <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> make this process straightforward by providing <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer" class="">targeting rules</a>, <a href="https://configcat.com/docs/targeting/percentage-options/" target="_blank" rel="noopener noreferrer" class="">percentage rollouts</a>, and a simple dashboard to control feature exposure without redeploying code. Because of this, both developers and product teams can safely manage feature releases and experiment directly in production.</p>
<p>If you'd like to try this rollout strategy yourself, you <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">can sign up for ConfigCat</a> and start using feature flags in minutes. ConfigCat offers a generous Forever Free plan, so you can experiment with gradual rollout and feature targeting without any upfront commitment. You can also follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a> to stay up to date with what we're building next.</p>]]></content:encoded>
            <category>canary release</category>
            <category>feature management</category>
            <category>progressive delivery</category>
            <category>how to</category>
            <category>legacy</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags in Bun (The New JavaScript Runtime)]]></title>
            <link>https://configcat.com/blog/feature-flags-in-bun/</link>
            <guid>https://configcat.com/blog/feature-flags-in-bun/</guid>
            <pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Understand feature flags in Bun, how they work, what they entail, and a step-by-step guide on how to implement feature flags in a Bun environment.]]></description>
            <content:encoded><![CDATA[<p>Bun is making waves in the JavaScript ecosystem. This speedy new toolkit promises faster startup times, native TypeScript support, and improved performance compared to Node.js. But as Bun gains adoption, developers require modern tooling to match its capabilities. Feature flags are one such tool, and are perfect for Bun applications.</p>
<p>Coming up, we'll learn what Bun is and how it compares to Node.js, then dive into using ConfigCat feature flags in Bun projects. Finally, we'll discuss how to safely roll out new features, A/B test them, and quickly fix problems in production, all with the help of feature flags.</p>
<img alt="Feature Flags in Bun cover" src="https://configcat.com/blog/assets/feature-flags-in-bun/feature-flags-in-bun-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-bun-bun-vs-nodejs">What is Bun? (Bun vs. Node.js)<a href="https://configcat.com/blog/feature-flags-in-bun/#what-is-bun-bun-vs-nodejs" class="hash-link" aria-label="Direct link to What is Bun? (Bun vs. Node.js)" title="Direct link to What is Bun? (Bun vs. Node.js)" translate="no">​</a></h2>
<p><a href="https://bun.com/" target="_blank" rel="noopener noreferrer" class="">Bun</a> was created as a JavaScript runtime replacement for Node.js. With added features like bundling, testing, and package management, it later became a toolkit for developing both JavaScript and TypeScript applications with better performance.</p>
<p>Here is a comparison between them:</p>
<table><thead><tr><th>Aspect</th><th>Bun</th><th>Node.js</th></tr></thead><tbody><tr><td>Startup Time</td><td>About 10 times faster</td><td>Slower to start up</td></tr><tr><td>TypeScript Support</td><td>Built in, no setup needed</td><td>Requires extra tools (ts-node, tsc, etc.)</td></tr><tr><td>Package Manager</td><td>Comes with one</td><td>Comes with npm (bundled with Node.js); can also use yarn, pnpm, etc.</td></tr><tr><td>How Fast It Runs</td><td>Very optimized</td><td>Mature and stable</td></tr><tr><td>Available Libraries</td><td>Growing</td><td>Huge selection (npm ecosystem)</td></tr><tr><td>Works Like Node.js</td><td>Mostly compatible</td><td>Industry standard</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-use-feature-flags-in-bun-applications">Why Use Feature Flags in Bun Applications?<a href="https://configcat.com/blog/feature-flags-in-bun/#why-use-feature-flags-in-bun-applications" class="hash-link" aria-label="Direct link to Why Use Feature Flags in Bun Applications?" title="Direct link to Why Use Feature Flags in Bun Applications?" translate="no">​</a></h2>
<p>Bun's speed and near-instant startup time make it an excellent choice for applications where behavior may need to change frequently. Feature flags complement this perfectly by allowing you to toggle features, run experiments, or adjust application behavior without a redeployment or app restart.</p>
<p>For command-line tools, Bun's fast startup means users get immediate responses. For serverless functions, faster cold starts translate to lower costs and better performance. However, raw speed alone isn't enough; software teams need to roll out changes safely, test new ideas with small user groups, and roll back quickly when something goes wrong.</p>
<p>This is exactly what feature flags provide. When combined with <a href="https://configcat.com/#product" target="_blank" rel="noopener noreferrer" class="">ConfigCat's feature management and remote configuration capabilities</a>, Bun applications gain:</p>
<ul>
<li class="">Real-time control over features and configuration</li>
<li class="">Safe, gradual rollouts instead of risky big releases</li>
<li class="">Instant kill switches for problematic code</li>
<li class="">Dynamic A/B testing without code changes</li>
<li class="">Flexible behavior for CLI tools, servers, and serverless environments</li>
</ul>
<p>In a nutshell, Bun gives you speed. Feature flags give you control. Together, they enable fast, reliable, and modern software delivery.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-use-feature-flags-in-bun-with-configcat">How to Use Feature Flags in Bun with ConfigCat<a href="https://configcat.com/blog/feature-flags-in-bun/#how-to-use-feature-flags-in-bun-with-configcat" class="hash-link" aria-label="Direct link to How to Use Feature Flags in Bun with ConfigCat" title="Direct link to How to Use Feature Flags in Bun with ConfigCat" translate="no">​</a></h2>
<p>To help you understand how to integrate ConfigCat feature flags in a Bun application or environment, here's a step-by-step guide:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-a-bun-project-and-install-the-bun-sdk">Step 1: Create a Bun Project and Install the Bun SDK<a href="https://configcat.com/blog/feature-flags-in-bun/#step-1-create-a-bun-project-and-install-the-bun-sdk" class="hash-link" aria-label="Direct link to Step 1: Create a Bun Project and Install the Bun SDK" title="Direct link to Step 1: Create a Bun Project and Install the Bun SDK" translate="no">​</a></h3>
<p>First, open a terminal and install bun:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install -g bun</span><br></div></code></pre></div></div>
<p>With Bun installed, create a new directory and initialize a Bun project using the following commands. When prompted, select <code>Blank</code> as the project template to use.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mkdir bun-feature-flags</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">cd bun-feature-flags</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">bun init</span><br></div></code></pre></div></div>
<p>Then, proceed to install the <a href="https://configcat.com/docs/sdk-reference/js/bun/" target="_blank" rel="noopener noreferrer" class="">ConfigCat Bun SDK</a>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">bun add @configcat/sdk</span><br></div></code></pre></div></div>
<p>Bun's package manager is really fast. The whole process of installing and setting it up takes a few seconds.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-initialize-the-configcat-client">Step 2: Initialize the ConfigCat Client<a href="https://configcat.com/blog/feature-flags-in-bun/#step-2-initialize-the-configcat-client" class="hash-link" aria-label="Direct link to Step 2: Initialize the ConfigCat Client" title="Direct link to Step 2: Initialize the ConfigCat Client" translate="no">​</a></h3>
<p>Create a reusable ConfigCat service so you can import and use it to evaluate feature flags throughout your application. In your Bun project, create a new file named <code>configcat.service.ts</code>, then paste the code below into the file.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports operator" style="color:rgb(137, 221, 255)">*</span><span class="token imports"> </span><span class="token imports keyword module" style="font-style:italic">as</span><span class="token imports"> configcat</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/sdk/bun"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  </span><span class="token imports maybe-class-name">PollingMode</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  type </span><span class="token imports maybe-class-name">IConfigCatClient</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  type </span><span class="token imports maybe-class-name">SettingValue</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  type </span><span class="token imports maybe-class-name">User</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports"></span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/sdk/bun"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> readonly client</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">IConfigCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> readonly </span><span class="token constant" style="color:rgb(130, 170, 255)">SDK_KEY</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR-CONFIGCAT-SDK-KEY"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">//Add your ConfigCat SDK key here.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> defaultUser</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> readonly </span><span class="token constant" style="color:rgb(130, 170, 255)">POLL_INTERVAL_SECONDS</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">30</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">constructor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">client</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SDK_KEY</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token maybe-class-name">PollingMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access maybe-class-name">AutoPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">pollIntervalSeconds</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">POLL_INTERVAL_SECONDS</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"ConfigCat initialization failed:"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get the value of a setting value</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getValue</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token constant" style="color:rgb(130, 170, 255)">T</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">SettingValue</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token literal-property property">defaultValue</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">T</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> user</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">client</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      defaultValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      user </span><span class="token operator" style="color:rgb(137, 221, 255)">??</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">defaultUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getAllValues</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">user</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">?</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">client</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getAllValuesAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      user </span><span class="token operator" style="color:rgb(137, 221, 255)">??</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">defaultUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">client</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">Symbol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Disposing ConfigCat Service"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Replace <strong>#YOUR-CONFIGCAT-SDK-KEY#</strong> with your actual <a href="https://app.configcat.com/sdkkey" target="_blank" rel="noopener noreferrer" class="">SDK key from ConfigCat</a>.</p></div></div>
<p>By using <a href="https://configcat.com/docs/sdk-reference/js/bun/#auto-polling-default" target="_blank" rel="noopener noreferrer" class="">AutoPoll</a>, the SDK periodically fetches your latest feature flag data every 60 seconds, so your flags remain in sync without requiring manual updates.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-evaluating-feature-flags">Step 3: Evaluating Feature Flags<a href="https://configcat.com/blog/feature-flags-in-bun/#step-3-evaluating-feature-flags" class="hash-link" aria-label="Direct link to Step 3: Evaluating Feature Flags" title="Direct link to Step 3: Evaluating Feature Flags" translate="no">​</a></h3>
<p>To evaluate feature flags, import the ConfigCat service into your Bun entry file (<code>index.ts</code>) and use it as shown below.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatService</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"./configcat.service"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createApp</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    using configCatService </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> isMyFeatureEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"myFeatureFlag"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"The feature flag value is: "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> isMyFeatureEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">createApp</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>With this setup, you can evaluate feature flags anywhere in your application.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="real-world-use-cases-for-bun-feature-flags">Real-World Use Cases for Bun Feature Flags<a href="https://configcat.com/blog/feature-flags-in-bun/#real-world-use-cases-for-bun-feature-flags" class="hash-link" aria-label="Direct link to Real-World Use Cases for Bun Feature Flags" title="Direct link to Real-World Use Cases for Bun Feature Flags" translate="no">​</a></h2>
<p>To build on what we previously learned, let's look at some practical use cases for using feature flags in a Bun environment or codebase.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="progressive-feature-rollout">Progressive Feature Rollout<a href="https://configcat.com/blog/feature-flags-in-bun/#progressive-feature-rollout" class="hash-link" aria-label="Direct link to Progressive Feature Rollout" title="Direct link to Progressive Feature Rollout" translate="no">​</a></h3>
<p>Imagine you're building a new API endpoint and want to test it with 10% of users first, then gradually increase to 100%.</p>
<p>Because ConfigCat's percentage targeting evaluates users deterministically, you can pass a User Object containing a unique identifier as the third parameter so users consistently fall into the rollout group.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatService</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"./configcat.service"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">handleRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter literal-property property">userId</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> string</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> </span><span class="token parameter literal-property property">request</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    using configCatService </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> newApiEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"new-api-endpoint"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userId </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// User Object</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">newApiEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">handleWithNewAPI</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">handleWithLegacyAPI</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>In <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's dashboard</a>, you can set the <code>new-api-endpoint</code> flag to target a percentage of users. As you gain confidence, you can increase the percentage without touching the actual code.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="ab-testing-in-bun-cli-tools">A/B Testing in Bun CLI Tools<a href="https://configcat.com/blog/feature-flags-in-bun/#ab-testing-in-bun-cli-tools" class="hash-link" aria-label="Direct link to A/B Testing in Bun CLI Tools" title="Direct link to A/B Testing in Bun CLI Tools" translate="no">​</a></h3>
<p>Bun also excels at CLI tools. Here's a way to run an A/B test experiment to evaluate two different  user experiences:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> parseArgs </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"util"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatService</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"./configcat.service"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    using configCatService </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> values </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">parseArgs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">options</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">user</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token literal-property property">type</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"string"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token literal-property property">short</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"u"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userId </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">user</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">||</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"anonymous"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> experimentVariant </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"ui-experiment-variant"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"control"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userId </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">experimentVariant </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"variant-b"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"User sees experience B"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Run variant B logic</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"User sees control experience"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Run control (variant A) logic</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token keyword control-flow" style="font-style:italic">catch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="serverless-functions-with-kill-switches">Serverless Functions with Kill Switches<a href="https://configcat.com/blog/feature-flags-in-bun/#serverless-functions-with-kill-switches" class="hash-link" aria-label="Direct link to Serverless Functions with Kill Switches" title="Direct link to Serverless Functions with Kill Switches" translate="no">​</a></h3>
<p>The start-up performance of Bun makes it ideal for serverless environments. Feature flags provide instant kill switches:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatService</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"./configcat.service"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">handler</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter literal-property property">event</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    using configCatService </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Check if the feature is experiencing issues</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> maintenanceMode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"maintenance-mode"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">maintenanceMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">statusCode</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">503</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token literal-property property">error</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Service temporarily unavailable"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Proceed with normal logic</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">statusCode</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">200</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">message</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Success"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>If your service degrades, you can toggle the flag off in ConfigCat without a code redeployment.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="advanced-configcat-features-in-bun">Advanced ConfigCat Features in Bun<a href="https://configcat.com/blog/feature-flags-in-bun/#advanced-configcat-features-in-bun" class="hash-link" aria-label="Direct link to Advanced ConfigCat Features in Bun" title="Direct link to Advanced ConfigCat Features in Bun" translate="no">​</a></h2>
<p>There are several advanced ConfigCat features for Bun that we can look into. Some of them are:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="targeting-rules">Targeting Rules<a href="https://configcat.com/blog/feature-flags-in-bun/#targeting-rules" class="hash-link" aria-label="Direct link to Targeting Rules" title="Direct link to Targeting Rules" translate="no">​</a></h3>
<p>ConfigCat allows you to define <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">targeting rules</a> for your feature flags, ensuring features are delivered to the right users based on attributes such as identifier, country, email, and more. Here's a simple example of how to implement it:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Sample user object</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userObject </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user@example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">email</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user@example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">country</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"US"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">custom</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">subscription</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"premium"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">joinDate</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"2023-01-15"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> premiumFeature </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"premium-analytics"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    userObject</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>In ConfigCat's dashboard, create a targeting rule: "<strong>If subscription equals premium, then Serve value: true</strong>". Now the flag will ensure that only users with a premium subscription see the feature.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-all-flag-values">Getting All Flag Values<a href="https://configcat.com/blog/feature-flags-in-bun/#getting-all-flag-values" class="hash-link" aria-label="Direct link to Getting All Flag Values" title="Direct link to Getting All Flag Values" translate="no">​</a></h3>
<p>For cases of dashboards or reporting, you can fetch all flags at once using the code below.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> allValues </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getAllValues</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user123"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">allValues</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">forEach</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">item</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">item</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">settingKey</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">item</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">settingValue</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="snapshots-for-synchronous-evaluation">Snapshots for Synchronous Evaluation<a href="https://configcat.com/blog/feature-flags-in-bun/#snapshots-for-synchronous-evaluation" class="hash-link" aria-label="Direct link to Snapshots for Synchronous Evaluation" title="Direct link to Snapshots for Synchronous Evaluation" translate="no">​</a></h3>
<p>Bun supports synchronous operations for flags already cached. The code below shows the implementation for that.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> snapshot </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> value </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"my-flag"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> userObject</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>This is perfect for synchronous code paths where async/await isn't practical.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="best-practices-for-feature-flags-in-bun">Best Practices for Feature Flags in Bun<a href="https://configcat.com/blog/feature-flags-in-bun/#best-practices-for-feature-flags-in-bun" class="hash-link" aria-label="Direct link to Best Practices for Feature Flags in Bun" title="Direct link to Best Practices for Feature Flags in Bun" translate="no">​</a></h2>
<p>To use feature flags in the best and most effective way, here are some best practices to look into.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-semantic-flag-names">Use Semantic Flag Names<a href="https://configcat.com/blog/feature-flags-in-bun/#use-semantic-flag-names" class="hash-link" aria-label="Direct link to Use Semantic Flag Names" title="Direct link to Use Semantic Flag Names" translate="no">​</a></h3>
<p>Name flags clearly to indicate their purpose:</p>
<ul>
<li class="">new-checkout-flow (better than words like feature-x, new-feature)</li>
<li class="">premium-analytics-dashboard (better than words like flag-123, test-flag)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="implement-proper-logging">Implement Proper Logging<a href="https://configcat.com/blog/feature-flags-in-bun/#implement-proper-logging" class="hash-link" aria-label="Direct link to Implement Proper Logging" title="Direct link to Implement Proper Logging" translate="no">​</a></h3>
<p>Feature flags can be difficult to debug without visibility into how values are evaluated. ConfigCat includes a built-in logger that helps you inspect flag evaluations and targeting decisions.</p>
<p>You can enable SDK logging when creating the client:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports operator" style="color:rgb(137, 221, 255)">*</span><span class="token imports"> </span><span class="token imports keyword module" style="font-style:italic">as</span><span class="token imports"> configcat</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/sdk/bun"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> configCatClient </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">CONFIGCAT_SDK_KEY</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access maybe-class-name">PollingMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access maybe-class-name">AutoPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">logger</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">createConsoleLogger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access maybe-class-name">LogLevel</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access maybe-class-name">Info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>With <strong>LogLevel.Info</strong>, the SDK logs:</p>
<ul>
<li class="">Feature flag evaluations</li>
<li class="">Targeting rule matches</li>
<li class="">Returned values</li>
</ul>
<p>This visibility makes it much easier to diagnose rollout issues and verify targeting behavior during development and testing.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-to-add-application-level-logging">When to Add Application-Level Logging<a href="https://configcat.com/blog/feature-flags-in-bun/#when-to-add-application-level-logging" class="hash-link" aria-label="Direct link to When to Add Application-Level Logging" title="Direct link to When to Add Application-Level Logging" translate="no">​</a></h3>
<p>While ConfigCat's logger is useful for diagnostics, you may still want to log business events for analytics, monitoring, or auditing.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> enabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"my-flag"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">enabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    auditLogger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Feature enabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">feature</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"my-flag"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>This type of logging is helpful for:</p>
<ul>
<li class="">Tracking feature adoption</li>
<li class="">Auditing behavior</li>
<li class="">Product analytics</li>
<li class="">Monitoring gradual rollouts</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cache-results-when-possible">Cache Results When Possible<a href="https://configcat.com/blog/feature-flags-in-bun/#cache-results-when-possible" class="hash-link" aria-label="Direct link to Cache Results When Possible" title="Direct link to Cache Results When Possible" translate="no">​</a></h3>
<p>For performance-critical code, cache the flag value during the request.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">handleRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter literal-property property">userId</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> flags </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">newUI</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"new-ui"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userId </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">analytics</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"advanced-analytics"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use flags.newUI and flags.analytics throughout the request</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// No additional flag evaluations needed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="clean-up-old-flags">Clean Up Old Flags<a href="https://configcat.com/blog/feature-flags-in-bun/#clean-up-old-flags" class="hash-link" aria-label="Direct link to Clean Up Old Flags" title="Direct link to Clean Up Old Flags" translate="no">​</a></h3>
<p>As features become permanent or experiments conclude, remove the corresponding flags to keep your codebase and dashboard clean.</p>
<p>Unused flags, often called <strong><a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">zombie flags</a></strong>, increase technical debt, complicate maintenance, and may trigger legacy logic unexpectedly.</p>
<p>ConfigCat helps you manage stale flags by:</p>
<ul>
<li class="">Identifying inactive flags in the Zombie Flags dashboard</li>
<li class="">Sending automated zombie flag email reports</li>
<li class="">Providing an API for cleanup automation</li>
</ul>
<p>If you enable <strong><a href="https://configcat.com/docs/advanced/code-references/overview/" target="_blank" rel="noopener noreferrer" class="">Code References</a></strong>, ConfigCat can show where a flag is used across your repositories, making it safer to remove unused flags.</p>
<p>You can go a step further by scanning your codebase with the ConfigCat CLI:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">configcat scan . --print</span><br></div></code></pre></div></div>
<p>This detects flag usage, highlights references to deleted flags, and helps prevent breaking changes during cleanup.</p>
<p>Regularly removing stale flags keeps your feature flag system maintainable and prevents long-term technical debt.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="document-flag-purpose">Document Flag Purpose<a href="https://configcat.com/blog/feature-flags-in-bun/#document-flag-purpose" class="hash-link" aria-label="Direct link to Document Flag Purpose" title="Direct link to Document Flag Purpose" translate="no">​</a></h3>
<p>In ConfigCat, you can add descriptions like:</p>
<ul>
<li class="">When the flag was created</li>
<li class="">What feature or experiment does it controls</li>
<li class="">The rollout strategy (gradual rollout, A/B test, internal only)</li>
<li class="">The expected removal date</li>
<li class="">The team or owner responsible</li>
</ul>
<p>Use <strong>tags</strong> to organize and filter flags at scale. For example:</p>
<ul>
<li class=""><code>experiment</code></li>
<li class=""><code>release</code></li>
<li class=""><code>ops</code></li>
<li class=""><code>beta</code></li>
<li class=""><code>cleanup-required</code></li>
</ul>
<p>Tags make it easier to track flags by purpose, environment, or lifecycle stage.</p>
<p>You can also include <strong>descriptive hints</strong> in the flag description to guide future developers, such as:</p>
<blockquote>
<p>"Temporary rollout flag for the new checkout flow. Remove after full rollout."</p>
</blockquote>
<p>Clear documentation reduces onboarding friction, prevents misuse, and makes flag cleanup safer and faster.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/feature-flags-in-bun/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Feature flags are no longer just a nice-to-have; they're essential for modern software delivery. Combined with Bun's performance and simplicity, they create a powerful foundation for building reliable, scalable applications.</p>
<p>Whether you're building CLI tools, serverless functions, or backend services, integrating ConfigCat feature flags in Bun takes minutes and pays dividends immediately.</p>
<p>Start with a simple kill switch. Progress to A/B testing. Eventually, you'll wonder how you ever shipped software without feature flags.</p>
<p>Ready to try it? Grab your Bun SDK key from ConfigCat and deploy your first feature flag today. Your users and your deployment pipeline will thank you.</p>
<p>You can also check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>how to</category>
            <category>feature flags</category>
            <category>feature management</category>
            <category>ConfigCat</category>
            <category>Bun</category>
        </item>
        <item>
            <title><![CDATA[How to Migrate from Prefab to ConfigCat Using MCP Server]]></title>
            <link>https://configcat.com/blog/migrate-from-prefab/</link>
            <guid>https://configcat.com/blog/migrate-from-prefab/</guid>
            <pubDate>Wed, 11 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to migrate your feature flags from Prefab to ConfigCat using Prefab CLI and the ConfigCat Model Context Protocol (MCP) server.]]></description>
            <content:encoded><![CDATA[<p>Manually recreating dozens of feature flags across platforms is tedious and error-prone. This guide shows you how to automate the entire migration from Prefab to ConfigCat in minutes using CLI export and natural language commands via an AI agent.</p>
<p>Rather than rebuilding every flag by hand, you'll export your entire Prefab configuration into a data file and use <a href="https://configcat.com/docs/advanced/mcp-server/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's AI-powered Model Context Protocol (MCP) server</a> to transfer your configuration with minimal effort.</p>
<p>Prefab was acquired by Reforge and is being rebranded as Reforge Launch. If you're evaluating <strong>Prefab alternatives</strong>, ConfigCat offers a comparable feature set. With this simple migration process, you can see exactly how your Prefab feature flags behave in ConfigCat.</p>
<img alt="Migrate Prefab feature flags to ConfigCat with MCP Servers" src="https://configcat.com/blog/assets/migrate-from-prefab/migrate-from-prefab-mcp-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr-how-to-migrate-from-prefab">TL;DR: How to Migrate from Prefab?<a href="https://configcat.com/blog/migrate-from-prefab/#tldr-how-to-migrate-from-prefab" class="hash-link" aria-label="Direct link to TL;DR: How to Migrate from Prefab?" title="Direct link to TL;DR: How to Migrate from Prefab?" translate="no">​</a></h2>
<ol>
<li class="">
<p>Use the <code>@prefab-cloud/prefab</code> CLI tool to download your Prefab feature flags as a <code>.json</code> data file.</p>
</li>
<li class="">
<p>Set up an AI agent (like <a href="https://claude.com/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a> or <a href="https://cursor.com/" target="_blank" rel="noopener noreferrer" class="">Cursor</a>) to connect to ConfigCat using the ConfigCat MCP server.</p>
</li>
<li class="">
<p>Ask the AI agent to interpret the exported file and migrate your feature flags from Prefab to ConfigCat.</p>
</li>
</ol>
<p>Read on for the full step-by-step walkthrough.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prefab-vs-configcat-how-the-concepts-map">Prefab vs. ConfigCat: How the Concepts Map<a href="https://configcat.com/blog/migrate-from-prefab/#prefab-vs-configcat-how-the-concepts-map" class="hash-link" aria-label="Direct link to Prefab vs. ConfigCat: How the Concepts Map" title="Direct link to Prefab vs. ConfigCat: How the Concepts Map" translate="no">​</a></h2>
<p>Before diving into the migration, it's helpful to understand how the two platforms map to each other conceptually.</p>
<ul>
<li class="">Prefab <strong>Feature Flags</strong> are equivalent to <strong>Boolean Feature Flags</strong> in ConfigCat (simple on/off toggles).</li>
<li class="">Prefab <strong>Config values</strong> (int, double, string, string list, JSON) map to <strong>Int</strong>, <strong>Double</strong> or <strong>String</strong> Settings in ConfigCat. JSON configs can be represented as a <strong>String Setting</strong> that stores the serialized JSON. A string list can also be mapped to a <strong>String Setting</strong> that stores comma-separated strings.</li>
<li class="">Both tools use <strong>Segments</strong> for reusable user groups, <strong>Targeting Rules</strong> for feature flag <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">targeting</a> and support multiple <strong>Environments</strong> like <em>Production</em>, <em>Staging</em>, <em>Dev</em>, etc.</li>
</ul>
<p>You can learn more about how ConfigCat structures <em>Settings</em>, <em>Products</em> and <em>Environments</em> in the <a href="https://configcat.com/docs/main-concepts/" target="_blank" rel="noopener noreferrer" class="">ConfigCat Main Concepts documentation</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://configcat.com/blog/migrate-from-prefab/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<ul>
<li class="">Prefab account with existing feature flags</li>
<li class="">ConfigCat account - <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">sign up for free</a>, if you don’t have one</li>
<li class=""><a href="https://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">Node.js</a> version 16 or higher installed</li>
<li class=""><a href="https://claude.com/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a> installed</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-export-your-prefab-feature-flags">Step 1: Export Your Prefab Feature Flags<a href="https://configcat.com/blog/migrate-from-prefab/#step-1-export-your-prefab-feature-flags" class="hash-link" aria-label="Direct link to Step 1: Export Your Prefab Feature Flags" title="Direct link to Step 1: Export Your Prefab Feature Flags" translate="no">​</a></h2>
<p>The <code>@prefab-cloud/prefab</code> CLI can download your entire Prefab configuration into a local <code>config.json</code> file. This file contains all your feature flags, config values, targeting rules, and segment definitions.</p>
<p>For this guide, assume you have these two feature flags in Prefab:</p>
<img alt="Prefab NewCheckoutFlow feature flag" src="https://configcat.com/blog/assets/migrate-from-prefab/new_checkout_flow_prefab_192dpi.png" width="922" height="589" decoding="async" loading="lazy" class="zoomable">
<img alt="Prefab BetaFeatures feature flag" src="https://configcat.com/blog/assets/migrate-from-prefab/beta_features_prefab_192dpi.png" width="922" height="544" decoding="async" loading="lazy" class="zoomable">
<p>This is the <strong>BetaUsers</strong> segment used by <strong>BetaFeatures</strong> feature flag:</p>
<img alt="Prefab BetaUsers segment" src="https://configcat.com/blog/assets/migrate-from-prefab/beta_users_segment_prefab_192dpi.png" width="922" height="589" decoding="async" loading="lazy" class="zoomable">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-the-prefab-cli">Install the Prefab CLI<a href="https://configcat.com/blog/migrate-from-prefab/#install-the-prefab-cli" class="hash-link" aria-label="Direct link to Install the Prefab CLI" title="Direct link to Install the Prefab CLI" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install -g @prefab-cloud/prefab</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-prefab-api-key">Create Prefab API Key<a href="https://configcat.com/blog/migrate-from-prefab/#create-prefab-api-key" class="hash-link" aria-label="Direct link to Create Prefab API Key" title="Direct link to Create Prefab API Key" translate="no">​</a></h3>
<p>The Prefab CLI tool needs an API key to access your feature flags.</p>
<p>Log in to your Prefab account and create an API key:</p>
<ol>
<li class="">Click <code>Environments</code>.</li>
<li class="">Click <code>Add Backend API Key</code> under the environment you want to migrate.</li>
<li class="">Copy the <code>Plain API Key</code>. The Prefab CLI will use this API key.</li>
<li class="">Click <code>OK</code>.</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="download-the-configuration-data-file">Download the configuration data file<a href="https://configcat.com/blog/migrate-from-prefab/#download-the-configuration-data-file" class="hash-link" aria-label="Direct link to Download the configuration data file" title="Direct link to Download the configuration data file" translate="no">​</a></h3>
<p>Let's export the configuration file of the <code>Development</code> environment:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">prefab download --api-key &lt;YOUR-PREFAB-BACKEND-API-KEY&gt; --environment Development</span><br></div></code></pre></div></div>
<p>This produces a <code>config.json</code> file in your working directory. It contains a complete snapshot of your Prefab flags. Keep this file handy, you'll upload it to the AI agent.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-configure-configcat-mcp-server">Step 2: Configure ConfigCat MCP Server<a href="https://configcat.com/blog/migrate-from-prefab/#step-2-configure-configcat-mcp-server" class="hash-link" aria-label="Direct link to Step 2: Configure ConfigCat MCP Server" title="Direct link to Step 2: Configure ConfigCat MCP Server" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-an-mcp-server">What is an MCP Server?<a href="https://configcat.com/blog/migrate-from-prefab/#what-is-an-mcp-server" class="hash-link" aria-label="Direct link to What is an MCP Server?" title="Direct link to What is an MCP Server?" translate="no">​</a></h3>
<p><a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol (MCP)</a> is an open standard that allows AI assistants to connect with external tools and services. Think of it as giving your AI agent hands to actually perform actions, not just talk about them.</p>
<p>An MCP server acts as a bridge between your AI client (like Claude Desktop) and an external service's API. When you ask your AI assistant to "list all feature flags in my project," the MCP server translates that natural language request into the appropriate API calls and lists your flags.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-configcat-public-api-credentials">Creating ConfigCat Public API Credentials<a href="https://configcat.com/blog/migrate-from-prefab/#creating-configcat-public-api-credentials" class="hash-link" aria-label="Direct link to Creating ConfigCat Public API Credentials" title="Direct link to Creating ConfigCat Public API Credentials" translate="no">​</a></h3>
<p>The <a href="https://configcat.com/docs/advanced/mcp-server/" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server</a> needs a ConfigCat Public API credential to access <a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's public management API</a> and perform actions like managing feature flags, targeting rules, or segments, etc.</p>
<p>You can create this credential on the <a href="https://app.configcat.com/my-account/public-api-credentials" target="_blank" rel="noopener noreferrer" class="">Public API credentials management page</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-mcp-server">Installing MCP Server<a href="https://configcat.com/blog/migrate-from-prefab/#installing-mcp-server" class="hash-link" aria-label="Direct link to Installing MCP Server" title="Direct link to Installing MCP Server" translate="no">​</a></h3>
<ol>
<li class="">Install <a href="https://claude.com/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a>, if you haven’t already.</li>
<li class="">Open <strong>Settings</strong> → <strong>Developer</strong></li>
<li class="">Click <strong>Edit Config</strong></li>
<li class="">In <code>claude_desktop_config.json</code> add:</li>
</ol>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"mcpServers"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"ConfigCat"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"command"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"npx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"-y"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/mcp-server"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"env"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_USER"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_CONFIGCAT_API_USER"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_PASS"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_CONFIGCAT_API_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<ol start="5">
<li class=""><strong>Save</strong> &amp; restart Claude Desktop.</li>
</ol>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Replace <code>YOUR_CONFIGCAT_API_USER</code> and <code>YOUR_CONFIGCAT_API_PASSWORD</code> environment variables with your <a href="https://app.configcat.com/my-account/public-api-credentials" target="_blank" rel="noopener noreferrer" class="">ConfigCat Public API credentials</a>.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="verify-the-mcp-server-connection">Verify the MCP Server Connection<a href="https://configcat.com/blog/migrate-from-prefab/#verify-the-mcp-server-connection" class="hash-link" aria-label="Direct link to Verify the MCP Server Connection" title="Direct link to Verify the MCP Server Connection" translate="no">​</a></h3>
<p>Let's try asking the agent to <strong>list all ConfigCat feature flags</strong> using the following prompt:</p>
<blockquote>
<p>"List all feature flags in my ConfigCat account"</p>
</blockquote>
<p>You should see a list of your ConfigCat feature flags with their names, IDs, and statuses. If this is a new ConfigCat account, you might see the default <code>myNewAwesomeFeature</code> flag created during registration.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>You’ll need to click <code>Run tool</code> or <code>Allow once</code> each time the AI agent tries to interact with the API. MCP servers require user approval before calling external APIs as a security measure. You can review the actual API request payload here before you accept it.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-migrate-the-feature-flags-to-configcat">Step 3: Migrate the Feature Flags to ConfigCat<a href="https://configcat.com/blog/migrate-from-prefab/#step-3-migrate-the-feature-flags-to-configcat" class="hash-link" aria-label="Direct link to Step 3: Migrate the Feature Flags to ConfigCat" title="Direct link to Step 3: Migrate the Feature Flags to ConfigCat" translate="no">​</a></h2>
<p>Upload the exported Prefab configuration data file, and let's ask the agent to migrate the first flag:</p>
<blockquote>
<p>"migrate <code>NewCheckoutFlow</code> Prefab feature flag into ConfigCat"</p>
</blockquote>
<p>On the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a>, you can check the migrated <code>NewCheckoutFlow</code> flag:</p>
<img alt="ConfigCat new_checkout_flow feature flag" src="https://configcat.com/blog/assets/migrate-from-prefab/new_checkout_flow_configcat_192dpi.png" width="907" height="549" decoding="async" loading="lazy" class="zoomable">
<p>Let's migrate the other one:</p>
<blockquote>
<p>"migrate <code>BetaFeatures</code> Prefab feature flag into ConfigCat"</p>
</blockquote>
<p>On the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a>, you can check the migrated <code>BetaFeatures</code> flag:</p>
<img alt="ConfigCat beta_features feature flag" src="https://configcat.com/blog/assets/migrate-from-prefab/beta_features_configcat_192dpi.png" width="907" height="433" decoding="async" loading="lazy" class="zoomable">
<p>This is the migrated <strong>BetaUsers</strong> segment used by the <strong>BetaFeatures</strong> feature flag:</p>
<img alt="Prefab BetaUsers segment" src="https://configcat.com/blog/assets/migrate-from-prefab/beta_users_segment_192dpi.png" width="907" height="684" decoding="async" loading="lazy" class="zoomable">
<p>The migration is complete. On top of that, you should update all usages of these flags in your codebase to use the appropriate <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">ConfigCat SDK</a> rather than the previous Prefab SDK.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>AI can make mistakes. Always validate and test the migrated feature flags.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="questions-you-might-have-during-migration">Questions You Might Have During Migration<a href="https://configcat.com/blog/migrate-from-prefab/#questions-you-might-have-during-migration" class="hash-link" aria-label="Direct link to Questions You Might Have During Migration" title="Direct link to Questions You Might Have During Migration" translate="no">​</a></h2>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="is-it-possible-to-remove-the-migrated-from-prefab-text-from-a-migrated-feature-flags-description">Is it possible to remove the <code>migrated from Prefab</code> text from a migrated feature flag's description?<a href="https://configcat.com/blog/migrate-from-prefab/#is-it-possible-to-remove-the-migrated-from-prefab-text-from-a-migrated-feature-flags-description" class="hash-link" aria-label="Direct link to is-it-possible-to-remove-the-migrated-from-prefab-text-from-a-migrated-feature-flags-description" title="Direct link to is-it-possible-to-remove-the-migrated-from-prefab-text-from-a-migrated-feature-flags-description" translate="no">​</a></h4>
<p>Yes. Add this requirement to your migration prompt like this:</p>
<blockquote>
<p>"Migrate <code>BetaFeatures</code> Prefab feature flag to ConfigCat. Keep the original description, don't append the text: <code>migrated from Prefab</code>."</p>
</blockquote>
<hr>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="is-configcat-a-good-prefab-alternative-for-teams-affected-by-the-reforge-acquisition">Is ConfigCat a good Prefab alternative for teams affected by the Reforge acquisition?<a href="https://configcat.com/blog/migrate-from-prefab/#is-configcat-a-good-prefab-alternative-for-teams-affected-by-the-reforge-acquisition" class="hash-link" aria-label="Direct link to Is ConfigCat a good Prefab alternative for teams affected by the Reforge acquisition?" title="Direct link to Is ConfigCat a good Prefab alternative for teams affected by the Reforge acquisition?" translate="no">​</a></h3>
<p>Yes. Prefab was acquired by Reforge and is being rebranded as Reforge Launch. For teams that want to stay on a dedicated, independent feature flag platform rather than follow the rebrand, ConfigCat is a strong alternative. It covers the same core use cases like boolean flags, multi-value settings, segments, targeting rules, and multiple environments, while also offering broader SDK support, global CDN delivery, transparent usage-based pricing with no seat limits, and a zero data collection architecture with strong security by design.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-i-migrate-flags-from-other-feature-flag-tools-like-launchdarkly">Can I migrate flags from other feature flag tools like LaunchDarkly?<a href="https://configcat.com/blog/migrate-from-prefab/#can-i-migrate-flags-from-other-feature-flag-tools-like-launchdarkly" class="hash-link" aria-label="Direct link to Can I migrate flags from other feature flag tools like LaunchDarkly?" title="Direct link to Can I migrate flags from other feature flag tools like LaunchDarkly?" translate="no">​</a></h4>
<p>For LaunchDarkly, ConfigCat has an <a href="https://configcat.com/docs/advanced/migration-from-launchdarkly/" target="_blank" rel="noopener noreferrer" class="">official migration tool</a> built into the ConfigCat dashboard.</p>
<p>For other tools (such as Statsig or DevCycle) that provide an MCP server, you can run a migration process that uses two MCP servers. The AI agent communicates with both servers and transfers the flags from the source tool via its MCP server to ConfigCat via the ConfigCat MCP server. This method is explained in detail in the following <a href="https://configcat.com/blog/migrate-from-statsig/" target="_blank" rel="noopener noreferrer" class="">blog post</a>.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-i-use-ai-to-refactor-the-usage-of-the-migrated-feature-flags-in-my-codebase">Can I use AI to refactor the usage of the migrated feature flags in my codebase?<a href="https://configcat.com/blog/migrate-from-prefab/#can-i-use-ai-to-refactor-the-usage-of-the-migrated-feature-flags-in-my-codebase" class="hash-link" aria-label="Direct link to Can I use AI to refactor the usage of the migrated feature flags in my codebase?" title="Direct link to Can I use AI to refactor the usage of the migrated feature flags in my codebase?" translate="no">​</a></h4>
<p>Yes. A ConfigCat MCP server can access the ConfigCat SDK documentation and assist with implementing ConfigCat feature flags.</p>
<p>It’s recommended to configure the ConfigCat MCP server in an AI coding tool such as <a href="https://cursor.com/" target="_blank" rel="noopener noreferrer" class="">Cursor</a>, <a href="https://github.com/anthropics/claude-code" target="_blank" rel="noopener noreferrer" class="">Claude Code</a>, or <a href="https://code.visualstudio.com/docs/copilot/setup" target="_blank" rel="noopener noreferrer" class="">VS Code with Copilot</a>. Just ask the AI tool to update the codebase like this:</p>
<blockquote>
<p>"Migrate my codebase from Prefab to ConfigCat for the "BetaFeatures" feature flag."</p>
</blockquote>
<p>AI-generated code may contain mistakes; always validate and test it.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="is-it-possible-to-use-configcats-hashed-confidential-text-comparators-instead-of-cleartext-comparators">Is it possible to use ConfigCat's hashed confidential text comparators instead of cleartext comparators?<a href="https://configcat.com/blog/migrate-from-prefab/#is-it-possible-to-use-configcats-hashed-confidential-text-comparators-instead-of-cleartext-comparators" class="hash-link" aria-label="Direct link to Is it possible to use ConfigCat's hashed confidential text comparators instead of cleartext comparators?" title="Direct link to Is it possible to use ConfigCat's hashed confidential text comparators instead of cleartext comparators?" translate="no">​</a></h4>
<p>Yes. Add this requirement to your prompt like this:</p>
<blockquote>
<p>"Migrate <code>NewCheckoutFlow</code> Prefab feature flag to ConfigCat. Use hashed ConfigCat confidential text comparators wherever possible instead of cleartext comparators."</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/migrate-from-prefab/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Migrating feature flags from Prefab to ConfigCat with the Prefab CLI tool and the ConfigCat MCP server is straightforward:</p>
<ol>
<li class="">Download the data file with the Prefab CLI tool</li>
<li class="">Set up ConfigCat MCP servers in your IDE</li>
<li class="">Export your complete environment into a data file from Prefab with the CLI tool</li>
<li class="">Load the exported data into the AI agent and ask to migrate the feature flags one by one</li>
<li class="">Verify and run both systems in parallel before cutover</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resources">Resources<a href="https://configcat.com/blog/migrate-from-prefab/#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://configcat.com/docs/advanced/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server documentation</a></li>
<li class=""><a href="https://github.com/configcat/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server GitHub repository</a></li>
<li class=""><a href="https://github.com/configcat/mcp-server?tab=readme-ov-file#available-tools" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server available tools</a></li>
<li class=""><a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">Management API Reference</a></li>
<li class=""><a href="https://configcat.com/docs/advanced/migration-from-launchdarkly/" target="_blank" rel="noopener noreferrer" class="">Official LaunchDarkly to ConfigCat migration tool</a></li>
<li class=""><a href="https://configcat.com/blog/migrate-from-statsig/" target="_blank" rel="noopener noreferrer" class="">How to Migrate from Statsig to ConfigCat: Feature Flag Migration Using MCP Servers - Blog post</a></li>
</ul>
<p>For more on feature flags, check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<p>If you're looking for a Prefab alternative, ConfigCat is a great choice. It does everything Prefab Reforge Launch does. <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">Sign up</a> and try it yourself or <a href="https://configcat.com/demo" target="_blank" rel="noopener noreferrer" class="">book a demo</a> to see it in action.</p>]]></content:encoded>
            <category>AI</category>
            <category>MCP server</category>
            <category>ConfigCat</category>
            <category>feature flags</category>
            <category>migration</category>
            <category>Prefab</category>
        </item>
        <item>
            <title><![CDATA[Feature Flag Variations: Structured Values for Multivariate and JSON Workflows]]></title>
            <link>https://configcat.com/blog/feature-flag-variations/</link>
            <guid>https://configcat.com/blog/feature-flag-variations/</guid>
            <pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Feature Flag Variations add structured, enum-like control to multivariate and JSON feature flags. Define once, reuse safely, reduce risk.]]></description>
            <content:encoded><![CDATA[<p>If you’ve ever wished your feature flag values worked more like <a href="https://en.wikipedia.org/wiki/Enumerated_type" target="_blank" rel="noopener noreferrer" class="">enums</a>, this update is for you.</p>
<p>Over the past years, we kept hearing the same request in different forms:</p>
<ul>
<li class=""><em>“Can we have enum-like values for feature flags?”</em></li>
<li class=""><em>“Can we avoid people mistyping values?”</em></li>
<li class=""><em>“Can we define JSON values once and just select it?”</em></li>
<li class=""><em>“Can we separate flag definitions from rollouts?”</em></li>
</ul>
<p>This usually came up when teams started using multivariate <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer" class="">feature flags</a> or working with more complex JSON feature flags.</p>
<p><a href="https://configcat.com/docs/main-concepts/#free-form-values-vs-predefined-variations" target="_blank" rel="noopener noreferrer" class="">Free-form values</a> are flexible. But when feature flags become operational tools, toggled by Customer Success, Sustainment teams, or junior teammates, flexibility without guardrails becomes a risk.</p>
<p><strong>So we built Predefined variations.</strong></p>
<img alt="ConfigCat Predefined Variations cover image" src="https://configcat.com/blog/assets/predef-variations/predefined-variations-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-feature-flag-variations">What Are Feature Flag Variations?<a href="https://configcat.com/blog/feature-flag-variations/#what-are-feature-flag-variations" class="hash-link" aria-label="Direct link to What Are Feature Flag Variations?" title="Direct link to What Are Feature Flag Variations?" translate="no">​</a></h2>
<p><a href="https://configcat.com/docs/advanced/predefined-variations/" target="_blank" rel="noopener noreferrer" class="">Predefined variations</a> let you define your possible feature flag values upfront. Instead of typing the value manually every time you create a targeting rule, you select it from a dropdown.</p>
<p>Each variation includes:</p>
<ul>
<li class="">Served value – the actual value returned to your application (including full JSON)</li>
<li class="">Display name – a human-readable label</li>
<li class="">Hint (optional) – guidance for when to use it</li>
</ul>
<p>In other words: define once, reuse safely.</p>
<p>If you’ve been looking for a way to implement a feature flag enum directly in the dashboard, this is it.</p>
<img class="zoomable" alt="ConfigCat Create Predifined Variations" src="https://configcat.com/blog/assets/predef-variations/predefined-variations-create_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="managing-json-feature-flags-without-copy-paste-drift">Managing JSON Feature Flags Without Copy-Paste Drift<a href="https://configcat.com/blog/feature-flag-variations/#managing-json-feature-flags-without-copy-paste-drift" class="hash-link" aria-label="Direct link to Managing JSON Feature Flags Without Copy-Paste Drift" title="Direct link to Managing JSON Feature Flags Without Copy-Paste Drift" translate="no">​</a></h2>
<p>Predefined variations are particularly useful for JSON feature flags.</p>
<p>Instead of embedding the full JSON object in every <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer" class="">targeting rule</a>, you define it once as a variation. That variation can then be reused consistently across environments and segments.</p>
<p>For example:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"display_name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Red Banner - Planned Outage"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"hint"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Use during confirmed production incidents"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"served_value"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"background_color"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"red"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"label"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Planned outage"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>Targeting rules then reference the variation by intent, not by repeating raw configuration.</p>
<p>This approach:</p>
<ul>
<li class="">Reduces duplication</li>
<li class="">Improves clarity in overview screens</li>
<li class="">Prevents small inconsistencies between environments</li>
<li class="">Makes flags safer for operational teams</li>
</ul>
<p>Definitions remain structured. Rollouts remain clean.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="supporting-multivariate-feature-flags-and-enum-workflows">Supporting Multivariate Feature Flags and Enum Workflows<a href="https://configcat.com/blog/feature-flag-variations/#supporting-multivariate-feature-flags-and-enum-workflows" class="hash-link" aria-label="Direct link to Supporting Multivariate Feature Flags and Enum Workflows" title="Direct link to Supporting Multivariate Feature Flags and Enum Workflows" translate="no">​</a></h2>
<p>Many teams use multivariate feature flags where values correspond to specific states in their application code. Often, these are mapped to enums on the backend.</p>
<p>With Predefined variations, the dashboard now mirrors that structure. Instead of typing arbitrary text or number values, you define the allowed options once and reuse them safely.</p>
<p>This reduces the chance of mismatched values and ensures consistency between the control plane and application logic.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="converting-existing-feature-flags">Converting Existing Feature Flags<a href="https://configcat.com/blog/feature-flag-variations/#converting-existing-feature-flags" class="hash-link" aria-label="Direct link to Converting Existing Feature Flags" title="Direct link to Converting Existing Feature Flags" translate="no">​</a></h2>
<p>Predefined Variations can be enabled on existing flags. When converting from free-form values to variations, the system automatically collects currently used values and suggests them as predefined options. You can then refine display names and hints.</p>
<p>You can also convert back to free-form values if needed. These conversions do not affect deployed applications.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-to-use-predefined-variations">When to Use Predefined Variations<a href="https://configcat.com/blog/feature-flag-variations/#when-to-use-predefined-variations" class="hash-link" aria-label="Direct link to When to Use Predefined Variations" title="Direct link to When to Use Predefined Variations" translate="no">​</a></h2>
<p>Predefined variations are a good fit when:</p>
<ul>
<li class="">You manage multivariate feature flags</li>
<li class="">You reuse complex JSON configurations</li>
<li class="">Non-engineers toggle production flags</li>
<li class="">You want enum-like control in the ConfigCat Dashboard</li>
<li class="">Consistency across environments matters</li>
</ul>
<p>Free-form values remain available for simple use cases. Variations add structure where structure reduces risk.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="available-in-all-plans">Available in All Plans<a href="https://configcat.com/blog/feature-flag-variations/#available-in-all-plans" class="hash-link" aria-label="Direct link to Available in All Plans" title="Direct link to Available in All Plans" translate="no">​</a></h2>
<p>Predefined variations are available across all <a href="https://configcat.com/pricing/" target="_blank" rel="noopener noreferrer" class="">ConfigCat plans</a>. They extend feature flag value management without adding complexity to rollout workflows.</p>
<p>Feature flags are meant to reduce deployment risk and improve operational control. As teams scale their usage, adding structure to feature flag values becomes a natural next step.</p>
<p>If you have feedback, <a href="https://configcat.com/support/" target="_blank" rel="noopener noreferrer" class="">we listen</a>. Many of the improvements in this release came directly from customer conversations.</p>
<p>You can also stay up-to-date with us on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>software release best practices</category>
            <category>how to</category>
            <category>customer feature request</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags for Startups: Meet the ConfigCat Startup Program]]></title>
            <link>https://configcat.com/blog/feature-flags-for-startups/</link>
            <guid>https://configcat.com/blog/feature-flags-for-startups/</guid>
            <pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[ConfigCat's Startup Program helps early-stage teams ship faster, reduce release risk, and grow using feature flags—without slowing down.]]></description>
            <content:encoded><![CDATA[<p>Shipping fast is part of startup life. Breaking production doesn't have to be.</p>
<p>Early-stage SaaS teams face a unique challenge: they need to ship new features quickly, experiment often, and release continuously without risking production stability. Speed drives growth, but uncontrolled releases can lead to outages, technical debt, and lost user trust. That's why feature flags have become a core part of modern startup release management.</p>
<p>The <a href="https://configcat.com/startup-program" target="_blank" rel="noopener noreferrer" class="">ConfigCat Startup Program</a> was created to help startups build with the right foundations from the beginning. It gives early-stage teams access to a production-ready feature flag service with startup-friendly pricing, so they can release safely while everything is still under construction.</p>
<img alt="ConfigCat Startup Program" src="https://configcat.com/blog/assets/startup-program/startup-program-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-do-startups-need-feature-flags-early">Why Do Startups Need Feature Flags Early<a href="https://configcat.com/blog/feature-flags-for-startups/#why-do-startups-need-feature-flags-early" class="hash-link" aria-label="Direct link to Why Do Startups Need Feature Flags Early" title="Direct link to Why Do Startups Need Feature Flags Early" translate="no">​</a></h2>
<p>Feature flags (also called feature toggles) allow teams to control when and how new functionality becomes visible to users without redeploying code. For startups practicing CI/CD and rapid iteration, this separation of deploy and release is critical.</p>
<p>Shipping fast is essential for startups - but moving quickly without control can cost momentum, trust, or even a weekend fixing production. That's where <strong>feature flags</strong> come in.</p>
<p>Feature flags let you:</p>
<ul>
<li class="">Separate deploys from releases</li>
<li class="">Test in production safely without exposing features to everyone</li>
<li class="">Roll out new functionality gradually</li>
<li class="">Instantly disable or adjust features when something goes wrong</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-hidden-cost-of-homegrown-feature-flags">The Hidden Cost of Homegrown Feature Flags<a href="https://configcat.com/blog/feature-flags-for-startups/#the-hidden-cost-of-homegrown-feature-flags" class="hash-link" aria-label="Direct link to The Hidden Cost of Homegrown Feature Flags" title="Direct link to The Hidden Cost of Homegrown Feature Flags" translate="no">​</a></h2>
<p>Many early-stage teams start with homegrown toggles: environment variables, config files, or simple flags in code. It works… for a little while.</p>
<p>But as your product grows, these shortcuts create <strong>tech debt</strong>:</p>
<ul>
<li class="">No rollback or gradual rollout options</li>
<li class="">Harder to test safely in multiple environments</li>
<li class="">Limited visibility and collaboration for your team</li>
<li class="">Complex refactors when scaling</li>
</ul>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> provides a production-ready feature flag management platform, giving you the flexibility of a homegrown system without the hidden maintenance costs, scaling issues, or operational risk.</p>
<p>⚡ <strong>Pro tip:</strong> Already using another feature flag platform like <a href="https://configcat.com/blog/how-to-migrate-from-launchdarkly-to-configcat/" target="_blank" rel="noopener noreferrer" class="">LaunchDarkly</a> or <a href="https://configcat.com/blog/migrate-from-statsig/" target="_blank" rel="noopener noreferrer" class="">Statsig</a>? ConfigCat offers migration guides so you can switch smoothly without disrupting production.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-we-created-the-configcat-startup-program">Why We Created the ConfigCat Startup Program<a href="https://configcat.com/blog/feature-flags-for-startups/#why-we-created-the-configcat-startup-program" class="hash-link" aria-label="Direct link to Why We Created the ConfigCat Startup Program" title="Direct link to Why We Created the ConfigCat Startup Program" translate="no">​</a></h2>
<p>At ConfigCat, we've seen startups struggle with two extremes:</p>
<ol>
<li class="">Building internal systems that don't scale</li>
<li class="">Avoid professional tooling due to budget limitations common in early-stage startups</li>
</ol>
<p>The Startup Program was designed to remove that trade-off. It provides early-stage teams with access to the same feature flag platform used in production by growing companies but with pricing and limits aligned to startup realities.</p>
<p>The goal isn't to add complexity. It's to give startups control over releases without complex setup.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-you-get-in-the-startup-program">What You Get in the Startup Program<a href="https://configcat.com/blog/feature-flags-for-startups/#what-you-get-in-the-startup-program" class="hash-link" aria-label="Direct link to What You Get in the Startup Program" title="Direct link to What You Get in the Startup Program" translate="no">​</a></h2>
<p>The Startup Program gives early-stage teams the full ConfigCat feature flag platform, plus startup-friendly benefits:</p>
<ul>
<li class=""><strong>50% off <a href="https://configcat.com/pricing/" target="_blank" rel="noopener noreferrer" class="">Pro or Smart annual plans</a> in Year 1</strong></li>
<li class=""><strong>25% off <a href="https://configcat.com/pricing/" target="_blank" rel="noopener noreferrer" class="">Pro or Smart annual plans</a> in Year 2</strong></li>
<li class=""><strong>Early access</strong> to upcoming new features</li>
</ul>
<p>This isn't a stripped-down edition. Teams get full feature flag capabilities, including:</p>
<ul>
<li class="">advanced <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/#what-is-a-targeting-rule" target="_blank" rel="noopener noreferrer" class="">targeting rules</a>,</li>
<li class=""><a href="https://configcat.com/docs/targeting/percentage-options/" target="_blank" rel="noopener noreferrer" class="">percentage-based rollouts</a>,</li>
<li class="">multiple <a href="https://configcat.com/docs/main-concepts/#environment" target="_blank" rel="noopener noreferrer" class="">environments</a> (development, staging, production),</li>
<li class="">remote configuration management,</li>
<li class="">generous monthly <a href="https://configcat.com/docs/requests/" target="_blank" rel="noopener noreferrer" class="">config.json downloads</a> and <a href="https://configcat.com/docs/network-traffic/" target="_blank" rel="noopener noreferrer" class="">network traffic</a> limits.</li>
</ul>
<p>You can start simple and scale when you're ready without refactoring your release infrastructure later.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-the-startup-program-compares-to-our-forever-free-plan">How the Startup Program Compares to Our Forever Free Plan<a href="https://configcat.com/blog/feature-flags-for-startups/#how-the-startup-program-compares-to-our-forever-free-plan" class="hash-link" aria-label="Direct link to How the Startup Program Compares to Our Forever Free Plan" title="Direct link to How the Startup Program Compares to Our Forever Free Plan" translate="no">​</a></h2>
<p>ConfigCat's <strong>Forever Free plan</strong> is great for prototypes or early experiments. The Startup Program is for teams building real products with real users. If you're building a hobby project or early prototype, the Forever Free plan may be enough.</p>
<table><thead><tr><th>Category</th><th>Forever Free Plan</th><th>Startup Program</th></tr></thead><tbody><tr><td>Best suited for</td><td>Prototypes, side projects, early validation</td><td>Early-stage startups building and scaling a live product</td></tr><tr><td>Monthly config.json downloads</td><td>Up to 5M/month</td><td>25M–250M (based on plan tier)</td></tr><tr><td>Network traffic</td><td>Up to 5GB/month</td><td>Higher traffic limits designed for growing products</td></tr><tr><td>Feature flags &amp; environments</td><td>Core feature flag functionality</td><td>Full feature flag platform with higher limits &amp; scalability</td></tr><tr><td>Targeting &amp; rollout capabilities</td><td>Available within Free limits</td><td>Advanced targeting and percentage rollouts at scale</td></tr><tr><td>Monthly Active Users (MAUs)</td><td>Unlimited</td><td>Unlimited (fixed pricing, no MAU-based surprises)</td></tr><tr><td>Pricing</td><td>Free</td><td>50% off Year 1, 25% off Year 2</td></tr></tbody></table>
<p>For a full breakdown of plan limits and details, see our <a href="https://configcat.com/pricing" target="_blank" rel="noopener noreferrer" class="">pricing page</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="who-the-startup-program-is-built-for">Who the Startup Program Is Built For<a href="https://configcat.com/blog/feature-flags-for-startups/#who-the-startup-program-is-built-for" class="hash-link" aria-label="Direct link to Who the Startup Program Is Built For" title="Direct link to Who the Startup Program Is Built For" translate="no">​</a></h2>
<p>The program is designed for <strong>early-stage startups</strong> actively building and shipping software.</p>
<p>Eligibility criteria:</p>
<ul>
<li class="">Company founded less than 5 years ago</li>
<li class="">Raised less than $5M USD in total funding</li>
<li class="">Live website or product</li>
<li class="">No paid ConfigCat subscription in the last 12 months</li>
</ul>
<p>Not sure if you qualify? <a href="https://configcat.com/startup-program" target="_blank" rel="noopener noreferrer" class="">Apply anyway</a>. We review applications individually, and the process typically takes up to one week.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-two-way-partnership">A Two-Way Partnership<a href="https://configcat.com/blog/feature-flags-for-startups/#a-two-way-partnership" class="hash-link" aria-label="Direct link to A Two-Way Partnership" title="Direct link to A Two-Way Partnership" translate="no">​</a></h2>
<p>The ConfigCat Startup Program is designed as a long-term partnership with early-stage teams.</p>
<p>Startups receive meaningful discounts and early access to new features. In return, participants share feedback and experiences as they grow with us.</p>
<p>Full details about participation and commitments are available on the <a href="https://configcat.com/startup-program" target="_blank" rel="noopener noreferrer" class="">Startup Program page</a>, where you can review everything before applying.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-join-configcats-startup-program">How to Join ConfigCat's Startup Program<a href="https://configcat.com/blog/feature-flags-for-startups/#how-to-join-configcats-startup-program" class="hash-link" aria-label="Direct link to How to Join ConfigCat's Startup Program" title="Direct link to How to Join ConfigCat's Startup Program" translate="no">​</a></h2>
<p>If your startup qualifies, you can apply directly through the Startup Program page.</p>
<p>Once approved, you can activate your discounted plan and begin using production-ready feature flags from day one.</p>
<p>👉 Visit the <a href="https://configcat.com/startup-program" target="_blank" rel="noopener noreferrer" class="">Startup Program page</a> to review the full details and submit your application.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-with-the-right-foundations">Start with the Right Foundations<a href="https://configcat.com/blog/feature-flags-for-startups/#start-with-the-right-foundations" class="hash-link" aria-label="Direct link to Start with the Right Foundations" title="Direct link to Start with the Right Foundations" translate="no">​</a></h2>
<p>Every startup builds while everything is still under construction. Features evolve. Assumptions change. Roadmaps shift. That’s the nature of building a startup.</p>
<p>What shouldn’t shift is your foundation.</p>
<p>The ConfigCat Startup Program helps early-stage teams build safely from day one, without enterprise pricing or unnecessary complexity.</p>
<p>If you are still validating ideas or building a prototype, you can start with our Forever Free plan. <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">Sign up here</a>, no credit card needed.  When you are ready to scale, the Startup Program gives you room to grow.</p>
<p>To learn more and apply, visit the <a href="https://configcat.com/startup-program" target="_blank" rel="noopener noreferrer" class="">Startup Program page</a>. You can also follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a> to stay up to date with what we're building next.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>startup</category>
            <category>saas</category>
        </item>
        <item>
            <title><![CDATA[ConfigCat's Favorite Feature Flags and the Biggest Blunder in Feature Flag History]]></title>
            <link>https://configcat.com/blog/biggest-blunder-in-feature-flag-history/</link>
            <guid>https://configcat.com/blog/biggest-blunder-in-feature-flag-history/</guid>
            <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover how we use feature flags in real life at ConfigCat and an embarrassing story about how not to use feature flags.]]></description>
            <content:encoded><![CDATA[<p>At ConfigCat, we use the best feature flag provider in the world. Plot twist: it's ConfigCat. We're basically in a committed relationship with ourselves. Some call it narcissism; we call it quality control.</p>
<p>In this article, we'll share real-world feature flag examples from production, explain how we use our own system inside ConfigCat, and confess the biggest feature flag mistake we've ever made (so you don't have to repeat it).</p>
<img alt="ConfigCat standoff" src="https://configcat.com/blog/assets/biggest-blunder/biggest-blunder-in-feature-flag-history-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-use-feature-flags-in-your-application">How to Use Feature Flags in Your Application?<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#how-to-use-feature-flags-in-your-application" class="hash-link" aria-label="Direct link to How to Use Feature Flags in Your Application?" title="Direct link to How to Use Feature Flags in Your Application?" translate="no">​</a></h2>
<p>At ConfigCat, we have a whopping number of 70 feature flags that control many different aspects of our applications on the backend and frontend sides as well.</p>
<p>We use feature flags to:</p>
<ul>
<li class="">Show targeted banners</li>
<li class="">Hide in-progress features</li>
<li class="">Run controlled experiments and A/B tests</li>
<li class="">Roll out new features gradually</li>
<li class="">Control beta access for selected users</li>
<li class="">Separate behavior across environments (dev, staging, production)</li>
<li class="">Flip emergency kill switches in production</li>
</ul>
<p>In practice, this means we can ship code safely, test ideas without risk, and react instantly when production gets... interesting.</p>
<p>Let me show you some real-world examples of how a feature flag tool utilizes feature flags.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-cute-one---the-issantahatvisible-feature-flag">The Cute One - the <code>isSantaHatVisible</code> Feature Flag<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#the-cute-one---the-issantahatvisible-feature-flag" class="hash-link" aria-label="Direct link to the-cute-one---the-issantahatvisible-feature-flag" title="Direct link to the-cute-one---the-issantahatvisible-feature-flag" translate="no">​</a></h2>
<p>During the holidays, we dress up our cute ConfigCat logo with a Santa hat on our login/signup pages.</p>
<img class="zoomable" alt="Santa hat" src="https://configcat.com/blog/assets/biggest-blunder/santa-hat_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<p>Yes, there is a feature flag for that. Yes, it's mission-critical.</p>
<img class="zoomable" alt="Santa flag" src="https://configcat.com/blog/assets/biggest-blunder/santa-flag_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<p>The code behind it is pretty simple yet so powerful. Instead of hardcoding dates, we check the current month and day and let configuration decide whether the hat appears.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">readonly isSantaHatVisible </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">resource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">loader</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> now </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"isSantaHatVisible"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"n/a"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token literal-property property">custom</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">month</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getUTCMonth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token literal-property property">day</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getUTCDate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-learning-one---comparatorsuggestionsforcomparisonattributes">The "Learning" One - <code>comparatorSuggestionsForComparisonAttributes</code><a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#the-learning-one---comparatorsuggestionsforcomparisonattributes" class="hash-link" aria-label="Direct link to the-learning-one---comparatorsuggestionsforcomparisonattributes" title="Direct link to the-learning-one---comparatorsuggestionsforcomparisonattributes" translate="no">​</a></h2>
<p>This feature flag's key is the proof that naming things is still one of the hardest problems in computer science.</p>
<p>We strive to build an intuitive interface that anticipates what customers need, making their workflow seamless and frictionless.</p>
<p>ConfigCat's <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer" class="">targeting rules</a> offer powerful <a href="https://configcat.com/docs/targeting/targeting-rule/user-condition/#comparator" target="_blank" rel="noopener noreferrer" class="">comparators</a> to help you build precise rollout strategies.
We launched with 15 comparators covering text, semantic versions, and numbers.
Fast forward to today: we now have 35 different comparators available.</p>
<p>More choice is great, but it came with a cost. We didn't want our customers spending too much time scrolling through irrelevant options. The solution? Context-aware filtering. Now, when you're building targeting rules around registration dates, we automatically surface datetime comparators. Working with app versions? You'll see semantic version comparators front and center, not text-based ones you'd never use.</p>
<p>Behind the scenes, a feature flag powers this intelligence. It takes the comparison attribute you've selected and returns the most appropriate comparators. We could have hardcoded these mappings, but that would have meant redeploying every time we wanted to tweak the logic.</p>
<p>This is an important point: feature flags are not just for hiding unfinished features. They can power adaptive product behavior in production without increasing deployment risk.</p>
<p><a href="https://configcat.com/support" target="_blank" rel="noopener noreferrer" class="">Let us know</a> if your comparison attributes are not showing the right comparators, and we'll try to adjust them.</p>
<img class="zoomable" alt="Comparator suggestions" src="https://configcat.com/blog/assets/biggest-blunder/comparators_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-guardian-angels---canuseconfigcat-isemailsendingenabled-disabledorganizationcreation">The Guardian Angels - <code>canUseConfigCat</code>, <code>isEmailSendingEnabled</code>, <code>disabledOrganizationCreation</code><a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#the-guardian-angels---canuseconfigcat-isemailsendingenabled-disabledorganizationcreation" class="hash-link" aria-label="Direct link to the-guardian-angels---canuseconfigcat-isemailsendingenabled-disabledorganizationcreation" title="Direct link to the-guardian-angels---canuseconfigcat-isemailsendingenabled-disabledorganizationcreation" translate="no">​</a></h2>
<p>Back in 2020, we launched our public <a href="https://configcat.com/bounty/" target="_blank" rel="noopener noreferrer" class="">Bug Bounty Program </a> without DDoS or firewall protections in front of our infrastructure. Basically, we walked into a gunfight with a butter knife. It didn't take long to realize we needed emergency parachutes inside the codebase.</p>
<p>So we added operational safety switches.</p>
<p>Email spammers trying to bankrupt us via our email provider? We deployed the <code>isEmailSendingEnabled</code> feature flag faster than you can say "captcha". (Of course, we later added proper CAPTCHA and infrastructure-level protections like responsible adults.)</p>
<p>Tired of manually deleting the 26th fake registration of <em><a href="mailto:admin@configcat.com" target="_blank" rel="noopener noreferrer" class="">admin@configcat.com</a></em>? <code>disabledOrganizationCreation</code> became our new best friend.</p>
<p>Spotted someone clearly up to no good? Time for feature flag jail with <code>canUseConfigCat</code>. Sorry, not sorry.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-does-this-matter">Why does this matter?<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#why-does-this-matter" class="hash-link" aria-label="Direct link to Why does this matter?" title="Direct link to Why does this matter?" translate="no">​</a></h3>
<p>These weren't "product" flags. They were operational <a href="https://configcat.com/docs/glossary/#kill-switch" target="_blank" rel="noopener noreferrer" class="">kill switches</a>. There's an important difference.</p>
<p>Every production system should have emergency controls that allow teams to:</p>
<ul>
<li class="">Disable high-risk subsystems instantly</li>
<li class="">Limit abuse without redeploying</li>
<li class="">Isolate suspicious accounts</li>
<li class="">Protect infrastructure while investigations are ongoing</li>
</ul>
<p>A deployment pipeline is not an incident-response mechanism. Feature flags, when designed properly, can act as one.</p>
<p>We've since added proper DDoS protection, firewall layers and abuse prevention mechanisms. But these switches remain as battle scars and as proof that runtime control can literally save your system when things go sideways.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-biggest-blunder-in-feature-flag-history---maintenancemodeenabled---aka-how-not-to-use-feature-flags">The Biggest Blunder in Feature Flag History - <code>maintenanceModeEnabled</code> - AKA How Not to Use Feature Flags?<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#the-biggest-blunder-in-feature-flag-history---maintenancemodeenabled---aka-how-not-to-use-feature-flags" class="hash-link" aria-label="Direct link to the-biggest-blunder-in-feature-flag-history---maintenancemodeenabled---aka-how-not-to-use-feature-flags" title="Direct link to the-biggest-blunder-in-feature-flag-history---maintenancemodeenabled---aka-how-not-to-use-feature-flags" translate="no">​</a></h2>
<p>Let me tell you about the time ConfigCat, the feature flag service provider, spectacularly failed at using feature flags.</p>
<p>We had a major database migration scheduled and needed a simple way to lock out customers temporarily. Easy, right? We're the feature flag experts after all!</p>
<p>The plan was foolproof:</p>
<ol>
<li class="">Create a <code>maintenanceModeEnabled</code> feature flag to be able to show a friendly "we'll be back soon" page. ✓</li>
<li class="">Turn on the feature flag. ✓</li>
<li class="">Execute the database migration. ✓ with flying colors.</li>
<li class="">Turn off the feature flag. ✗ Houston, we have a problem.</li>
</ol>
<img alt="Maintenance" src="https://configcat.com/blog/assets/biggest-blunder/maintenance_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<p>Turns out, when you enable a feature flag that blocks <em>everyone</em> from accessing your dashboard, that includes <em>you</em>. Who knew? (Literally everyone but us, apparently.)</p>
<p>Picture us: the feature flag experts locked out of their own feature flag system, SSH-ing into the database server to manually flip a Boolean in production.  Peak DevOps energy.</p>
<p>Let's not talk about eating your own <del>dog</del> cat food.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-actually-went-wrong">What actually went wrong?<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#what-actually-went-wrong" class="hash-link" aria-label="Direct link to What actually went wrong?" title="Direct link to What actually went wrong?" translate="no">​</a></h3>
<p>The problem wasn't feature flags. The problem was architecture. We tied operational control to the same access path it was supposed to regulate. In simpler terms: the switch that locked users out also locked out the people who needed to unlock it.</p>
<p>That's not resilience. That's self-inflicted downtime.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-real-lesson">The real lesson<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#the-real-lesson" class="hash-link" aria-label="Direct link to The real lesson" title="Direct link to The real lesson" translate="no">​</a></h3>
<p>Maintenance mode (and any critical kill switch) must follow a few rules:</p>
<ul>
<li class="">Always include admin bypass logic</li>
<li class="">Separate operational control from user-facing access</li>
<li class="">Provide an out-of-band recovery path</li>
<li class="">Test lockout scenarios before enabling them in production</li>
</ul>
<p>A maintenance flag should never depend on the system it might disable. That's not just a funny story. It's a design principle.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/biggest-blunder-in-feature-flag-history/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Feature flags are incredibly versatile tools. They can make your life easier, your deployments safer, and your customers happier. But as we've learned the hard way, they're not just convenience switches. But once they control production behavior, they become infrastructure. And infrastructure deserves discipline.</p>
<p>The real power of feature flags isn't just that they let you ship faster, it's that they let you correct course quickly when things don't go as planned.</p>
<p>Used well, they reduce risk. Used carelessly, they create it.</p>
<p>If you're ready to start your own feature flag journey (minus the face-palm moments), <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> offers a <a href="https://configcat.com/pricing" target="_blank" rel="noopener noreferrer" class="">forever free plan</a> to help you get started. And don't worry, we've fixed the <code>maintenanceModeEnabled</code> flag since then (Pinky promise!)</p>
<p>You can also follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a> to stay up to date with what we're building next.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>education</category>
            <category>best practices</category>
            <category>story</category>
        </item>
        <item>
            <title><![CDATA[How to Migrate from Statsig to ConfigCat: Feature Flag Migration Using MCP Servers]]></title>
            <link>https://configcat.com/blog/migrate-from-statsig/</link>
            <guid>https://configcat.com/blog/migrate-from-statsig/</guid>
            <pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to migrate your feature flags from Statsig to ConfigCat using natural-language prompts with Model Context Protocol (MCP) servers.]]></description>
            <content:encoded><![CDATA[<p>In this step-by-step guide, you’ll learn how to automate your Statsig feature flags migration with AI-powered Model Context Protocol (MCP) servers.
Instead of writing custom scripts or manually recreating each flag, you can use natural language commands to transfer your entire configuration reducing migration time by up to 80%.</p>
<img alt="Migrate Statsig feature flags to ConfigCat with MCP Servers" src="https://configcat.com/blog/assets/migrate-from-statsig/migrate-from-statsig-mcp-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr-how-to-migrate-from-statsig">TL;DR: How to Migrate from Statsig?<a href="https://configcat.com/blog/migrate-from-statsig/#tldr-how-to-migrate-from-statsig" class="hash-link" aria-label="Direct link to TL;DR: How to Migrate from Statsig?" title="Direct link to TL;DR: How to Migrate from Statsig?" translate="no">​</a></h2>
<p>We are going to set up an AI agent (like <a href="https://claude.com/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a> or <a href="https://cursor.com/" target="_blank" rel="noopener noreferrer" class="">Cursor</a>) to connect to Statsig through the Statsig MCP server and to ConfigCat through the ConfigCat MCP server. After that, you can simply ask the AI agent to migrate your feature flags from Statsig to ConfigCat. Let’s see how to do this step by step.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="differences-between-statsig-and-configcat">Differences between Statsig and ConfigCat<a href="https://configcat.com/blog/migrate-from-statsig/#differences-between-statsig-and-configcat" class="hash-link" aria-label="Direct link to Differences between Statsig and ConfigCat" title="Direct link to Differences between Statsig and ConfigCat" translate="no">​</a></h2>
<p>Before diving into the migration, it's helpful to understand how the two platforms map to each other conceptually. While ConfigCat and Statsig share many similar features and concepts,
they use different terminology and have some structural differences.</p>
<ul>
<li class="">Statsig <strong>Feature Gates</strong> are equivalent to <strong>Boolean Feature Flags</strong> in ConfigCat (simple on/off toggles).</li>
<li class="">Statsig <strong>Dynamic Configs</strong> store JSON payloads. In ConfigCat, the equivalent is a <strong>String Setting</strong> that stores the JSON as a string.</li>
<li class="">Statsig <strong>Rules</strong> map to <strong>Targeting Rules</strong> in ConfigCat.</li>
<li class="">Both tools use <strong>Segments</strong> for reusable user groups for targeting and support multiple <strong>Environments</strong> like <em>Production</em>, <em>Staging</em>, <em>Dev</em>, etc.</li>
</ul>
<p>You can learn more about how ConfigCat structures <em>Settings</em>, <em>Products</em> and <em>Environments</em> in the <a href="https://configcat.com/docs/main-concepts/" target="_blank" rel="noopener noreferrer" class="">ConfigCat Main Concepts documentation</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://configcat.com/blog/migrate-from-statsig/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<ul>
<li class="">Statsig account</li>
<li class=""><a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">ConfigCat account</a> - If you don’t have one yet, <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">sign up here for free</a></li>
<li class=""><a href="https://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">Node.js</a> version 16 or higher installed</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-mcp-servers">What are MCP Servers?<a href="https://configcat.com/blog/migrate-from-statsig/#what-are-mcp-servers" class="hash-link" aria-label="Direct link to What are MCP Servers?" title="Direct link to What are MCP Servers?" translate="no">​</a></h2>
<p><a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol (MCP)</a> is an open standard that allows AI assistants to connect with external tools and services. Think of it as giving your AI agent hands to actually perform actions, not just talk about them.</p>
<p>An MCP server acts as a bridge between your AI client (like Claude Desktop) and an external service's API. When you ask your AI assistant to "list all feature flags in my project," the MCP server translates that natural language request into the appropriate API calls and lists your flags.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-configcat-public-api-credentials">Creating ConfigCat Public API Credentials<a href="https://configcat.com/blog/migrate-from-statsig/#creating-configcat-public-api-credentials" class="hash-link" aria-label="Direct link to Creating ConfigCat Public API Credentials" title="Direct link to Creating ConfigCat Public API Credentials" translate="no">​</a></h2>
<p>The <a href="https://configcat.com/docs/advanced/mcp-server/" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server</a> needs a ConfigCat Public API credential to access the <a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's public management API</a> and perform actions like managing feature flags, targeting rules or segments etc.</p>
<p>You can create this credential on the <a href="https://app.configcat.com/my-account/public-api-credentials" target="_blank" rel="noopener noreferrer" class="">Public API credentials management page</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-statsig-console-api-key">Creating Statsig Console API Key<a href="https://configcat.com/blog/migrate-from-statsig/#creating-statsig-console-api-key" class="hash-link" aria-label="Direct link to Creating Statsig Console API Key" title="Direct link to Creating Statsig Console API Key" translate="no">​</a></h2>
<p>The Statsig MCP server also needs Statsig Console API key to access the Statsig API via the MCP server.</p>
<p>Login to your Statsig account and create a console API key:</p>
<ol>
<li class="">Settings -&gt; Keys &amp; Environments</li>
<li class="">Click <code>Generate New Key</code></li>
<li class="">Select <code>Console</code> Key Type</li>
<li class="">Add a description like <code>MCP console key for migration to ConfigCat</code></li>
<li class="">Enable Any Environment or Select specified one</li>
<li class="">Click <code>Create</code></li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-mcp-servers">Installing MCP Servers<a href="https://configcat.com/blog/migrate-from-statsig/#installing-mcp-servers" class="hash-link" aria-label="Direct link to Installing MCP Servers" title="Direct link to Installing MCP Servers" translate="no">​</a></h2>
<ol>
<li class="">Install <a href="https://claude.ai/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a>, if you haven’t already.</li>
<li class="">Open <strong>Settings</strong> → <strong>Developer</strong></li>
<li class="">Click <strong>Edit Config</strong></li>
<li class="">In <code>claude_desktop_config.json</code> add:</li>
</ol>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"mcpServers"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"ConfigCat"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"command"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"npx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"-y"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/mcp-server"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"env"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_USER"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_CONFIGCAT_API_USER"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_PASS"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_CONFIGCAT_API_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"Statsig"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"command"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"npx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"mcp-remote"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"https://api.statsig.com/v1/mcp"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"--header"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"statsig-api-key:${AUTH_TOKEN}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"env"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"AUTH_TOKEN"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_STATSIG_AUTH_TOKEN"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<ol start="5">
<li class=""><strong>Save</strong> &amp; restart Claude Desktop.</li>
</ol>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Replace <code>YOUR_CONFIGCAT_API_USER</code> and <code>YOUR_CONFIGCAT_API_PASSWORD</code> environment variables with your <a href="https://app.configcat.com/my-account/public-api-credentials" target="_blank" rel="noopener noreferrer" class="">ConfigCat Public API credentials</a>.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Replace <code>YOUR_STATSIG_AUTH_TOKEN</code> environment variables with your <strong>Statsig Console API Key</strong>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="verify-the-mcp-server-connections">Verify the MCP Server Connections<a href="https://configcat.com/blog/migrate-from-statsig/#verify-the-mcp-server-connections" class="hash-link" aria-label="Direct link to Verify the MCP Server Connections" title="Direct link to Verify the MCP Server Connections" translate="no">​</a></h2>
<p>Let's try asking the agent to <strong>list all Statsig flags</strong> using the following prompt:</p>
<blockquote>
<p>"List all feature gates in my Statsig account"</p>
</blockquote>
<p>You should see a list of your Statsig feature flags with their names, IDs and statuses.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>You’ll need to click <code>Run tool</code> or <code>Allow once</code> each time the AI agent tries to interact with the API. MCP servers require user approval before calling external APIs as a security measure. You can review the actual API request payload here before you accept it.</p></div></div>
<p>Let's do the same with the ConfigCat account</p>
<blockquote>
<p>"List all feature flags in my ConfigCat account"</p>
</blockquote>
<p>You should see a list of your ConfigCat feature flags. If this is a new ConfigCat account, you might see the default <code>myNewAwesomeFeature</code> flag created during registration.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-migration-process">The Migration Process<a href="https://configcat.com/blog/migrate-from-statsig/#the-migration-process" class="hash-link" aria-label="Direct link to The Migration Process" title="Direct link to The Migration Process" translate="no">​</a></h2>
<p>The migration follows a simple two-step workflow: first export everything from Statsig, then create each flag in ConfigCat.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="export-your-statsig-feature-gates">Export Your Statsig Feature Gates<a href="https://configcat.com/blog/migrate-from-statsig/#export-your-statsig-feature-gates" class="hash-link" aria-label="Direct link to Export Your Statsig Feature Gates" title="Direct link to Export Your Statsig Feature Gates" translate="no">​</a></h3>
<p>Let's assume in Statsig you have these two feature gates:</p>
<img alt="Statsig beta_features feature flag" src="https://configcat.com/blog/assets/migrate-from-statsig/beta_features_statsig_192dpi.png" width="922" height="577" decoding="async" loading="lazy" class="zoomable">
<img alt="Statsig new_checkout_flow feature flag" src="https://configcat.com/blog/assets/migrate-from-statsig/new_checkout_flow_statsig_192dpi.png" width="922" height="651" decoding="async" loading="lazy" class="zoomable">
<p>Start by getting a complete inventory of your flags. Use this prompt:</p>
<blockquote>
<p>"List all feature gates in my Statsig project. For each gate, show me: name, description, status, default value and all targeting rules with their conditions."</p>
</blockquote>
<p>Save this output. It becomes your migration checklist and reference for creating flags in ConfigCat.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="migrate-the-feature-flags-to-configcat">Migrate the Feature Flags to ConfigCat<a href="https://configcat.com/blog/migrate-from-statsig/#migrate-the-feature-flags-to-configcat" class="hash-link" aria-label="Direct link to Migrate the Feature Flags to ConfigCat" title="Direct link to Migrate the Feature Flags to ConfigCat" translate="no">​</a></h3>
<p>Let's ask the agent to migrate the first flag:</p>
<blockquote>
<p>"migrate <code>beta_features</code> Statsig feature gate into ConfigCat"</p>
</blockquote>
<p>On the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a> you can check the migrated <code>beta_features</code> flag:</p>
<img alt="ConfigCat beta_features feature flag" src="https://configcat.com/blog/assets/migrate-from-statsig/beta_features_configcat_192dpi.png" width="907" height="429" decoding="async" loading="lazy" class="zoomable">
<p>Let's migrate the other one:</p>
<blockquote>
<p>"migrate <code>new_checkout_flow</code> Statsig feature gate into ConfigCat"</p>
</blockquote>
<p>On the ConfigCat dashboard you can check the second flag:</p>
<img alt="ConfigCat new_checkout_flow feature flag" src="https://configcat.com/blog/assets/migrate-from-statsig/new_checkout_flow_configcat_192dpi.png" width="907" height="549" decoding="async" loading="lazy" class="zoomable">
<p>The migration is complete. On top of that, you should update all usages of these flags in your codebase to use the appropriate <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">ConfigCat SDK</a> rather than the previous Statsig SDK.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>AI can make mistakes. Always validate and test the migrated feature flags.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="questions-you-might-have-during-migration">Questions You Might Have During Migration<a href="https://configcat.com/blog/migrate-from-statsig/#questions-you-might-have-during-migration" class="hash-link" aria-label="Direct link to Questions You Might Have During Migration" title="Direct link to Questions You Might Have During Migration" translate="no">​</a></h2>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="is-it-possible-to-remove---migrated-from-statsig-text-from-a-migrated-feature-flags-description">Is it possible to remove <code>- migrated from Statsig</code> text from a migrated feature flag's description?<a href="https://configcat.com/blog/migrate-from-statsig/#is-it-possible-to-remove---migrated-from-statsig-text-from-a-migrated-feature-flags-description" class="hash-link" aria-label="Direct link to is-it-possible-to-remove---migrated-from-statsig-text-from-a-migrated-feature-flags-description" title="Direct link to is-it-possible-to-remove---migrated-from-statsig-text-from-a-migrated-feature-flags-description" translate="no">​</a></h4>
<p>Yes. Add this requirement to your migration prompt like this:</p>
<blockquote>
<p>"Migrate <code>beta_features</code> Statsig feature gate into ConfigCat. Keep the original description don't append the text: <code>- migrated from Statsig</code>"</p>
</blockquote>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-i-migrate-dynamic-configs-or-parameter-stores">Can I migrate Dynamic Configs or Parameter Stores?<a href="https://configcat.com/blog/migrate-from-statsig/#can-i-migrate-dynamic-configs-or-parameter-stores" class="hash-link" aria-label="Direct link to Can I migrate Dynamic Configs or Parameter Stores?" title="Direct link to Can I migrate Dynamic Configs or Parameter Stores?" translate="no">​</a></h4>
<p>A Statsig <code>Dynamic Config</code> will be migrated into ConfigCat as a <code>String Setting</code> storing a JSON string.</p>
<p>Unfortunately, the Statsig MCP server can’t access <code>Parameter Stores</code>, so they can’t be migrated using the method described in this blog post.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-i-migrate-flags-from-other-feature-flag-tools-like-launchdarkly">Can I migrate flags from other feature flag tools like LaunchDarkly?<a href="https://configcat.com/blog/migrate-from-statsig/#can-i-migrate-flags-from-other-feature-flag-tools-like-launchdarkly" class="hash-link" aria-label="Direct link to Can I migrate flags from other feature flag tools like LaunchDarkly?" title="Direct link to Can I migrate flags from other feature flag tools like LaunchDarkly?" translate="no">​</a></h4>
<p>For LaunchDarkly, ConfigCat has an <a href="https://configcat.com/docs/advanced/migration-from-launchdarkly/" target="_blank" rel="noopener noreferrer" class="">official migration tool</a> built into the ConfigCat dashboard.</p>
<p>For other tools (for example DevCycle) that provide an MCP server, you can run a similar migration process as described above.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-i-use-ai-to-refactor-the-usage-of-the-migrated-feature-flags-in-my-codebase">Can I use AI to refactor the usage of the migrated feature flags in my codebase?<a href="https://configcat.com/blog/migrate-from-statsig/#can-i-use-ai-to-refactor-the-usage-of-the-migrated-feature-flags-in-my-codebase" class="hash-link" aria-label="Direct link to Can I use AI to refactor the usage of the migrated feature flags in my codebase?" title="Direct link to Can I use AI to refactor the usage of the migrated feature flags in my codebase?" translate="no">​</a></h4>
<p>Yes. A ConfigCat MCP server can access the ConfigCat SDK documentation and assist with implementing ConfigCat feature flags.</p>
<p>It’s recommended to configure the ConfigCat MCP server in an AI coding tool such as <a href="https://cursor.com/" target="_blank" rel="noopener noreferrer" class="">Cursor</a>, <a href="https://github.com/anthropics/claude-code" target="_blank" rel="noopener noreferrer" class="">Claude Code</a>, or <a href="https://code.visualstudio.com/docs/copilot/setup" target="_blank" rel="noopener noreferrer" class="">VS Code with Copilot</a>. Just ask the AI tool to update the codebase like this:</p>
<blockquote>
<p>"Migrate my codebase from Statsig to ConfigCat for the "beta_features" feature flag."</p>
</blockquote>
<p>AI-generated code may contain mistakes, always validate and test it.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-i-migrate-statsig-experiments">Can I migrate Statsig experiments?<a href="https://configcat.com/blog/migrate-from-statsig/#can-i-migrate-statsig-experiments" class="hash-link" aria-label="Direct link to Can I migrate Statsig experiments?" title="Direct link to Can I migrate Statsig experiments?" translate="no">​</a></h4>
<p>Statsig experiments can be mapped to ConfigCat’s <a href="https://configcat.com/docs/targeting/percentage-options/" target="_blank" rel="noopener noreferrer" class="">percentage-based targeting</a> rules.<br>
<!-- -->You can migrate your experiment groups using the following prompt:</p>
<blockquote>
<p>“Migrate the <code>my_experiment</code> Statsig experiment into ConfigCat as a feature flag with percentage-based targeting for each variant.”</p>
</blockquote>
<p>Because ConfigCat follows a <strong>zero data collection</strong> strategy, it does not collect user-tracking data. For statistical analysis, you’ll need to integrate an analytics tool such as <a href="https://configcat.com/docs/integrations/google-analytics/" target="_blank" rel="noopener noreferrer" class="">Google Analytics</a> or <a href="https://configcat.com/docs/integrations/mixpanel/" target="_blank" rel="noopener noreferrer" class="">Mixpanel</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/migrate-from-statsig/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Migrating feature flags from Statsig to ConfigCat with MCP servers is straightforward:</p>
<ol>
<li class="">Set up both MCP servers in your IDE</li>
<li class="">Export your complete flag list from Statsig</li>
<li class="">Ask the AI agent to migrate the feature flags one by one</li>
<li class="">Verify and run both systems in parallel before cutover</li>
</ol>
<p>What previously took hours of manual work now becomes a series of copy-paste prompts. The AI handles the API complexity while you focus on ensuring your flags are correctly configured.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resources">Resources<a href="https://configcat.com/blog/migrate-from-statsig/#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://configcat.com/docs/advanced/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server documentation</a></li>
<li class=""><a href="https://github.com/configcat/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server GitHub repository</a></li>
<li class=""><a href="https://github.com/configcat/mcp-server?tab=readme-ov-file#available-tools" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server available tools</a></li>
<li class=""><a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">Management API Reference</a></li>
<li class=""><a href="https://configcat.com/docs/advanced/migration-from-launchdarkly/" target="_blank" rel="noopener noreferrer" class="">Official LaunchDarkly to ConfigCat migration tool</a></li>
</ul>
<p>For more on feature flags, check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a> and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<p>If you’re a Statsig user and you’re interested in how migrating to ConfigCat works in practice, <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">sign up</a> and try it yourself or <a href="https://configcat.com/demo" target="_blank" rel="noopener noreferrer" class="">book a demo</a> to see it in action.</p>]]></content:encoded>
            <category>AI</category>
            <category>MCP server</category>
            <category>ConfigCat</category>
            <category>feature flags</category>
            <category>migration</category>
            <category>Statsig</category>
        </item>
        <item>
            <title><![CDATA[Chaos Engineering with Feature Flags: Testing Resilience Through Controlled Failures]]></title>
            <link>https://configcat.com/blog/chaos-engineering-with-feature-flags/</link>
            <guid>https://configcat.com/blog/chaos-engineering-with-feature-flags/</guid>
            <pubDate>Fri, 30 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How chaos-enabled feature flags let teams test resilience through controlled failures without risking production reliability.]]></description>
            <content:encoded><![CDATA[<p>Most teams agree that reliability is learned in production, but the real challenge is learning without affecting the customer experience. After all, even well-designed systems fail in subtle ways: a single slow dependency can cascade into bottlenecks, or an overloaded database connection can push response times beyond what users will tolerate. We can wait for incidents to expose these cracks, or simulate them on our own with the help of feature flags.</p>
<p>Chaos engineering with feature flags offers a more controlled alternative. Instead of waiting for failures to happen, teams can deliberately inject small, realistic faults into production, limit their blast radius, and observe how systems behave under stress without risking a full-scale incident.</p>
<p>In this article, we'll look at how feature flags work, how they fit naturally into chaos engineering practices, and how chaos-enabled feature flags can help test production resilience through controlled failures.</p>
<img alt="chaos Engineering with Feature Flags" src="https://configcat.com/blog/assets/chaos-enabled-flags/chaos-enabled-feature-flags-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-feature-flags">What are feature flags?<a href="https://configcat.com/blog/chaos-engineering-with-feature-flags/#what-are-feature-flags" class="hash-link" aria-label="Direct link to What are feature flags?" title="Direct link to What are feature flags?" translate="no">​</a></h2>
<p>A <a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer" class="">feature flag</a> is a software technique that functions like a remote switch inside your app. It is typically a boolean value that can be coupled with conditional statements in your code to enable or disable features or functionality without requiring a redeployment.</p>
<p>In the context of chaos engineering, feature flags are especially useful because they let you introduce and remove failure behavior in production without redeploying code.</p>
<p>Modern feature flag management platforms go further. Tools like <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> allow you to configure your features with <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">targeting and percentage rules</a> to target a specific region, device, or <a href="https://configcat.com/docs/targeting/targeting-rule/segment-condition/" target="_blank" rel="noopener noreferrer" class="">user segment</a>.</p>
<p>Here are a few common ways in which feature flags are used:</p>
<ul>
<li class=""><strong>Release flags</strong> - Gradually expose a new feature to 1%, then 5%, then 25% of users. Roll back to zero with a single click if needed.</li>
<li class=""><strong>Operational flags</strong> - Switch off a heavy job, reduce cache TTLs, or enable a fallback implementation.</li>
<li class=""><strong>Experiment flags</strong> - Direct a user segment to variant A or B for learning or A/B testing.</li>
<li class=""><strong>Kill switches</strong> - Provide an emergency stop for malfunctioning features.</li>
</ul>
<p>Chaos flags fall into that second group. They give engineers the ability to simulate degraded conditions or trigger controlled failures without deploying new code.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-quick-primer-on-chaos-engineering">A quick primer on chaos engineering<a href="https://configcat.com/blog/chaos-engineering-with-feature-flags/#a-quick-primer-on-chaos-engineering" class="hash-link" aria-label="Direct link to A quick primer on chaos engineering" title="Direct link to A quick primer on chaos engineering" translate="no">​</a></h2>
<p><a href="https://principlesofchaos.org/" target="_blank" rel="noopener noreferrer" class="">Chaos engineering</a> is the practice of forming a hypothesis about a system’s steady state and then running experiments that challenge that assumption. You define what “normal” looks like in metrics and traces, pick a failure mode that could realistically occur, inject that failure in a controlled way, observe what changes, and learn where your controls or fallbacks are weak — then fix them.</p>
<p>Common failure modes include added latency, dropped requests, dependency timeouts, resource exhaustion, network partitions, and bad data. The most valuable experiments run close to production scale — ideally in production — which is where most teams start to get nervous. That’s where feature flags come in.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="chaos-engineering-with-feature-flags">Chaos engineering with feature flags<a href="https://configcat.com/blog/chaos-engineering-with-feature-flags/#chaos-engineering-with-feature-flags" class="hash-link" aria-label="Direct link to Chaos engineering with feature flags" title="Direct link to Chaos engineering with feature flags" translate="no">​</a></h2>
<p>The ideal way to test the resilience and reliability of software is to incorporate chaos engineering practices.</p>
<p>Just relying on traditional chaos engineering tools like fault injection proxies, service mesh experiments, and traffic replays is powerful but often heavy to operate and hard to scope. When combined with feature flags, you get:</p>
<ul>
<li class=""><strong>Precision targeting</strong> - Scope by environment, service, percentage of traffic, user segment, or geographic region.</li>
<li class=""><strong>Instant rollback</strong> - Toggling a flag is faster and less stressful than reverting a deployment.</li>
<li class=""><strong>Auditability</strong> - Flags live in a control plane with change history, ownership, and approvals.</li>
<li class=""><strong>Consistency</strong> - The same mechanisms used for dark launches, <a href="https://configcat.com/blog/2022/02/09/How-to-do-Canary-Release-Progressive-Delivery-with-ConfigCat/" target="_blank" rel="noopener noreferrer" class="">canary rollouts</a>, and kill switches can drive failure simulations.</li>
</ul>
<p>Chaos engineering provides a way to probe weak spots by introducing deliberate faults. Feature flags allow us to toggle functionality on or off. Combine the two, and you get <strong>chaos-enabled feature flags</strong> — flags designed not just to enable features, but to enable failure: deliberately, safely, and reversibly.</p>
<p>Think of it as a practical, reversible way to test resilience under real traffic. Flip one toggle, and a small, well-chosen slice of users experience added latency, a dependency failure, or a throttled resource — while everyone else remains unaffected. Measure how the system bends, not just whether it breaks. Learn, adjust, and repeat.</p>
<p>For example, imagine you want to test how your application handles a slow database. With a chaos flag, you can inject artificial latency for a targeted subset of users:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">App</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  using configCatService </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userObject </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getUserObject</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> canInjectLatency </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'chaosDatabaseLatency'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    userObject</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">canInjectLatency</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Simulate a slow database latency: add 500-2000ms of delay</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> delay </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">Math</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">random</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1500</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">500</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Simulating a </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">delay</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">ms database delay...</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Promise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">resolve</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setTimeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">resolve</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Normal database call</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userProfile </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getUserProfileFromDatabase</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'User Profile:'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> userProfile</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>This approach makes reliability testing a regular habit, integrating it into delivery rather than treating it as a special event. You don’t need a large platform team or a heavy chaos toolchain to get started — but you do need discipline, observability, and a few sensible guardrails.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benefits-of-chaos-enabled-feature-flags-for-resilience-testing">Benefits of chaos-enabled feature flags for resilience testing<a href="https://configcat.com/blog/chaos-engineering-with-feature-flags/#benefits-of-chaos-enabled-feature-flags-for-resilience-testing" class="hash-link" aria-label="Direct link to Benefits of chaos-enabled feature flags for resilience testing" title="Direct link to Benefits of chaos-enabled feature flags for resilience testing" translate="no">​</a></h2>
<p>Using feature flags for chaos engineering offers several practical advantages.</p>
<ul>
<li class=""><strong>Safer production learning</strong> - Flags carry built-in safety: progressive exposure, instant rollback, approvals, and visibility. This reduces the risk of a chaos test turning into a public incident.</li>
<li class=""><strong>Realistic conditions</strong> - Lab tests miss emergent behavior that only shows up with real caches, real network paths, and messy user patterns. Flags let you get real conditions with low risk.</li>
<li class=""><strong>No redeploy needed</strong> - Feature flags let you run experiments during a code freeze because you can toggle behavior without deploying new code.</li>
<li class=""><strong>Documentation for free</strong> - Flags with metadata, audit logs, and notes give you a history of how the system reacted under stress, helping future on-call engineers to troubleshoot faster.</li>
<li class=""><strong>Precision and repeatability</strong> - Traditional chaos tools often operate at a lower layer, which can be noisy or broad. Feature flags let you aim faults at specific parts of your code, then repeat the same scenario weeks later to validate a fix.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="guardrails-for-safe-chaos-engineering-in-production">Guardrails for safe chaos engineering in production<a href="https://configcat.com/blog/chaos-engineering-with-feature-flags/#guardrails-for-safe-chaos-engineering-in-production" class="hash-link" aria-label="Direct link to Guardrails for safe chaos engineering in production" title="Direct link to Guardrails for safe chaos engineering in production" translate="no">​</a></h2>
<p>Chaos engineering works best with boundaries. Most production incidents caused by experiments aren't due to bad ideas; they're caused by missing guardrails.</p>
<p>Here are the ones that matter in practice:</p>
<ul>
<li class=""><strong>Start small:</strong> Start with an internal cohort, then grow carefully. Production experiments can begin with employees, test accounts, or canary tenants.</li>
<li class=""><strong>Time limits:</strong> Define how long the chaos flag should remain active. You can do so by adding a TTL on the flag or an automation that turns it off after a set window.</li>
<li class=""><strong>SLO-aware automation:</strong> Wire the flag to your alert pipeline so that if the experiment degrades user experience, the system kills it automatically, notifies the team, and logs what happened.</li>
<li class=""><strong>Full observability:</strong> Log the evaluated flag values with each request. Add them as attributes on traces and as labels on metrics. That makes before-and-after comparisons straightforward and prevents you from chasing phantom regressions.</li>
<li class=""><strong>Single ownership:</strong> Every flag should have a runbook entry and a named owner or team. Document what it does, how long it should live, rollout plan, rollback plan, and expected signals or metrics.</li>
<li class=""><strong>Isolation across environments:</strong> Keep separate flag keys or namespaces per environment. If one misconfiguration can enable a flag everywhere at once, you're one typo away from an outage.</li>
<li class=""><strong>Change review:</strong> Treat a chaos flag toggle like a production change. Use the same approval workflow you use for risky config edits. The approval process adds enough friction to make you think twice before flipping a toggle.</li>
<li class=""><strong>Cleanup discipline:</strong> Retire the flag as soon as the learning is recorded. Don't let <a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">zombie flags</a> pile up, as they create technical debt, add cognitive load, and can cause surprise interactions.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/chaos-engineering-with-feature-flags/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Chaos-enabled feature flags give you the best parts of two proven ideas. You get real production experiments and the safety of tight controls. You can target, define a time window, and roll back in seconds. You can turn reliability from a big quarterly event into a weekly practice that fits inside normal delivery.</p>
<p>Start with a service and one failure mode. Inject a little delay, then watch what happens. Fix the sharp edges you find. Share the outcome with the team. Then move to a second failure mode. Over time, you’ll accumulate a clear catalog of experiments and the practice to run them well. Your systems won't just pass health checks—they’ll behave reliably even under stress.</p>
<p>The goal is not perfection, but rather steady, deliberate learning with small bumps along the way and an easy path back to calm. If you're looking for a practical way to get started, a feature flag management platform like <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> gives you the controls needed to run controlled failure experiments without disrupting users. The <a href="https://configcat.com/pricing" target="_blank" rel="noopener noreferrer" class="">forever free plan</a> is enough to begin experimenting with feature flags and resilience testing today.</p>
<p>You can also stay up-to-date with ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>chaos engineering</category>
            <category>reliability</category>
            <category>testing</category>
        </item>
        <item>
            <title><![CDATA[Top 8 LaunchDarkly Alternatives in 2025]]></title>
            <link>https://configcat.com/blog/top-eight-launchdarkly-alternatives/</link>
            <guid>https://configcat.com/blog/top-eight-launchdarkly-alternatives/</guid>
            <pubDate>Tue, 09 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover 8 top LaunchDarkly alternatives—best feature flag tools to try for modern dev teams in 2025 and beyond.]]></description>
            <content:encoded><![CDATA[<p>Feature flags save lives (okay, at least your weekends). They let you release features safely, test ideas with real users, and roll back when things break.</p>
<p>LaunchDarkly is the biggest name in the game, but it's not always the best fit. Maybe you need simple pricing, zero data collection, or an open-source option you can self-host. The good news: there are amazing Launchdarkly alternatives out there.</p>
<p>Here are <strong>the 8 best feature flag tools in 2025</strong> to help you ship faster, safer, and stress-free.</p>
<img alt="Top eight LaunchDarkly alternatives" src="https://configcat.com/blog/assets/top-eight-launchdarkly-alternatives/top-eight-launchdarkly-alternatives-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-configcat---simple-transparent-and-built-for-teams-of-all-shapes-and-sizes">1. ConfigCat - Simple, Transparent, and Built for Teams of All Shapes and Sizes<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#1-configcat---simple-transparent-and-built-for-teams-of-all-shapes-and-sizes" class="hash-link" aria-label="Direct link to 1. ConfigCat - Simple, Transparent, and Built for Teams of All Shapes and Sizes" title="Direct link to 1. ConfigCat - Simple, Transparent, and Built for Teams of All Shapes and Sizes" translate="no">​</a></h2>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> is one of the most popular LaunchDarkly alternatives for teams who want essential feature flagging capabilities (user targeting, percentage rollouts, audit logs, enterprise-grade security, and blazing-fast SDKs) minus the clutter and surprises. Flat usage-based pricing (no per-seat or MAU charges), unlimited team members, zero end-user data collection, and a zero-pressure Forever Free plan make ConfigCat the feature-flagging companion that always lands on its feet.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-choose-configcat">Why teams choose ConfigCat<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-choose-configcat" class="hash-link" aria-label="Direct link to Why teams choose ConfigCat" title="Direct link to Why teams choose ConfigCat" translate="no">​</a></h3>
<ul>
<li class="">Unlimited team members on all plans: invite everyone without extra cost</li>
<li class="">Flat, transparent, usage-based pricing (no per‑seat/MAU fees)</li>
<li class="">Zero data collection architecture: flags are evaluated on client side, user data doesn't go to ConfigCat by default</li>
<li class="">Blazing fast, global feature flag delivery</li>
<li class="">Data residency control (EU, global CDNs, configurable governance)</li>
<li class=""><a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">Rich SDK set</a> across backend, frontend, mobile, game engines, and more</li>
<li class=""><a href="https://configcat.com/docs/advanced/migration-from-launchdarkly/" target="_blank" rel="noopener noreferrer" class="">Free LaunchDarkly-to-ConfigCat migration tool</a> for fast onboarding</li>
<li class=""><a href="https://configcat.com/docs/sdk-reference/openfeature/overview/" target="_blank" rel="noopener noreferrer" class="">OpenFeature support</a> for easier integration and less lock-in</li>
<li class="">Hosted, private cloud, and on-prem options</li>
<li class="">Adorable cat logo 🐾</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Forever Free plan: 10 flags, 2 environments, 2 products, unlimited team members, 5M <a href="https://configcat.com/docs/requests/" target="_blank" rel="noopener noreferrer" class="">config.json downloads</a>/month, unlimited seats</li>
<li class="">Pro: Starts at $110/mo (100 flags, 3 envs/products, higher network limits)</li>
<li class="">Higher tiers: From $325/mo, unlimited flags &amp; increased usage limits</li>
<li class="">All plans include customer support, advanced targeting, and enterprise features like SSO/SAML and SCIM</li>
</ul>
<p><strong>Best for you if:</strong> you want a simple, scalable feature flag solution with unlimited seats, predictable pricing, and no hidden usage traps.</p>
<p><strong>Less ideal if:</strong> you need deeply integrated built-in statistics for experimentation (you can still run experiments by combining ConfigCat with your analytics/data warehouse).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-flagsmith---open-source-with-self-hosting-flexibility">2. Flagsmith - Open Source with Self-Hosting Flexibility<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#2-flagsmith---open-source-with-self-hosting-flexibility" class="hash-link" aria-label="Direct link to 2. Flagsmith - Open Source with Self-Hosting Flexibility" title="Direct link to 2. Flagsmith - Open Source with Self-Hosting Flexibility" translate="no">​</a></h2>
<p><a href="https://www.flagsmith.com/" target="_blank" rel="noopener noreferrer" class="">Flagsmith</a> is built for teams that love open source and want to shape their feature flag system to fit their world. If fine-tuning YAML brings you the same quiet joy a cat gets from finding a new sleeping spot, Flagsmith is your tool.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-choose-flagsmith">Why teams choose Flagsmith<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-choose-flagsmith" class="hash-link" aria-label="Direct link to Why teams choose Flagsmith" title="Direct link to Why teams choose Flagsmith" translate="no">​</a></h3>
<ul>
<li class="">100% open-source, so you can see (and change) the code</li>
<li class="">Flexible deployment: fully on-prem, private cloud, or in their SaaS</li>
<li class="">A/B and multivariate testing built into the platform</li>
<li class="">OpenFeature support so you can swap vendors without changing app code</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-1">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-1" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Free plan: Unlimited flags and environments, 1 user/month, up to 50k requests/month</li>
<li class="">Start-up plan: $45/mo, 3 members, 1M requests</li>
<li class="">Enterprise plans: Custom pricing, 5M+ requests, premium support, private cloud/on-prem</li>
</ul>
<p><strong>Best for you if:</strong> you want open source + SaaS flexibility.</p>
<p><strong>Less ideal if:</strong> you want a totally managed experience with no infra involvement (Flagsmith's SaaS is managed, but many teams adopt it precisely to later self-host).</p>
<p>Also, if you plan to self-host the open source version but still need enterprise governance: the OSS self-hosted setup doesn’t include things like role-based access control, audit logs, and guaranteed support/SLAs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-splitio-harness-fme---enterprise-grade-experimentation--observability">3. Split.io (Harness FME) - Enterprise-Grade Experimentation &amp; Observability<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#3-splitio-harness-fme---enterprise-grade-experimentation--observability" class="hash-link" aria-label="Direct link to 3. Split.io (Harness FME) - Enterprise-Grade Experimentation &amp; Observability" title="Direct link to 3. Split.io (Harness FME) - Enterprise-Grade Experimentation &amp; Observability" translate="no">​</a></h2>
<p><a href="https://www.split.io/" target="_blank" rel="noopener noreferrer" class="">Split.io</a> gives you feature flags with a scientific twist: built-in experiments, guardrails, and impact metrics that reveal exactly how your features behave. Since joining the Harness family in May 2024, Split has become part of a larger enterprise toolkit designed to keep your releases as controlled as a cat stalking its prey.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-choose-splitio">Why teams choose Split.io<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-choose-splitio" class="hash-link" aria-label="Direct link to Why teams choose Split.io" title="Direct link to Why teams choose Split.io" translate="no">​</a></h3>
<ul>
<li class="">Strong focus on experimentation and feature observability</li>
<li class="">Instant Feature Impact Detection (IFID) to spot issues during rollouts</li>
<li class="">Advanced user targeting, gradual rollouts, and dynamic configuration</li>
<li class="">40+ integrations across development, monitoring, and infrastructure</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-2">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-2" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Free trial available</li>
<li class="">Team plan: $33/user/month (min. 10 users)</li>
<li class="">Business plan: $60/user/month (min. 10 users) with full experimentation features</li>
<li class="">Enterprise: Custom quotes for advanced capabilities and premium support</li>
</ul>
<p><strong>Best for you if:</strong> you’re an enterprise already using Harness or planning to consolidate tools.</p>
<p><strong>Less ideal if:</strong> you want flat, non-seat-based pricing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-unleash---open-source-flags-with-enterprise-ready-governance">4. Unleash - Open-Source Flags with Enterprise-Ready Governance<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#4-unleash---open-source-flags-with-enterprise-ready-governance" class="hash-link" aria-label="Direct link to 4. Unleash - Open-Source Flags with Enterprise-Ready Governance" title="Direct link to 4. Unleash - Open-Source Flags with Enterprise-Ready Governance" translate="no">​</a></h2>
<p><a href="https://www.getunleash.io/" target="_blank" rel="noopener noreferrer" class="">Unleash</a> is a fully open-source platform that lets you deploy feature flags wherever you prefer: on-prem, in your own cloud, or even on that Raspberry Pi you keep meaning to repurpose. It’s ideal for teams who value freedom and control, much like a cat who insists on managing its own schedule.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-choose-unleash">Why teams choose Unleash<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-choose-unleash" class="hash-link" aria-label="Direct link to Why teams choose Unleash" title="Direct link to Why teams choose Unleash" translate="no">​</a></h3>
<ul>
<li class="">Open-source with a large, mature community</li>
<li class="">Flexible deployment: self‑host, private cloud, or Unleash‑hosted SaaS</li>
<li class="">Detailed audit trails and role-based access for compliance</li>
<li class="">Gradual rollout strategies for custom targeting</li>
<li class="">Real-time feedback and instant rollbacks</li>
<li class="">Huge SDK library (official and community-supported)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-3">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-3" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Self-hosted plan: Free forever, includes all core features and unlimited flags</li>
<li class="">Managed (SaaS): Paid plans scale by usage, number of environments, and enterprise features (SSO, SLAs, etc.)</li>
</ul>
<p><strong>Best for you if:</strong> you want open‑source control, strong compliance, and flexibility to run Unleash anywhere.</p>
<p><strong>Less ideal if:</strong> you need built‑in experimentation &amp; analytics in one product.</p>
<p>In the self-hosted open-source (OSS) version, there’s no SSO, SCIM, or Role-Based Access Control (RBAC) either.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-posthog---the-all-in-one-analytics-and-feature-flag-platform">5. PostHog - The All-in-One Analytics and Feature Flag Platform<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#5-posthog---the-all-in-one-analytics-and-feature-flag-platform" class="hash-link" aria-label="Direct link to 5. PostHog - The All-in-One Analytics and Feature Flag Platform" title="Direct link to 5. PostHog - The All-in-One Analytics and Feature Flag Platform" translate="no">​</a></h2>
<p><a href="https://posthog.com/" target="_blank" rel="noopener noreferrer" class="">PostHog</a> is the Swiss Army knife of product teams: feature flags, product analytics, A/B testing, session replay, and user surveys, all in a single open-source platform. Self-host or go cloud and enjoy unlimited flags in the OSS edition. It’s the perfect mix of hedgehog precision and cat-like curiosity for understanding what your users really do.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-like-posthog">Why teams like PostHog<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-like-posthog" class="hash-link" aria-label="Direct link to Why teams like PostHog" title="Direct link to Why teams like PostHog" translate="no">​</a></h3>
<ul>
<li class="">Self-hosted OSS or Cloud with generous free tier</li>
<li class="">Feature flags tightly integrated with analytics and experiments</li>
<li class="">Session replay &amp; surveys beside flags</li>
<li class="">Integrates with your data warehouse</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-4">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-4" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Open‑source (self‑hosted): Free forever, unlimited feature flags, but A/B testing is not available in the OSS edition</li>
<li class="">Cloud: starts at $0/mo with 1M events/month, then pay‑as‑you‑go pricing for additional events and features (replay, advance analytics, etc.).</li>
</ul>
<p><strong>Best for you if:</strong> you want an all‑in‑one solution combining feature flags, analytics, and user insights in one place.</p>
<p><strong>Less ideal if:</strong> you only need lightweight flagging without the overhead of of a big analytics suite.</p>
<p>Also, the free self-hosted OSS version doesn’t include features like SAML/SSO, RBAC, account management, or audit logs. It's not optimized for scaling to very high event volumes. PostHog recommends paid cloud plans if you need to handle more events.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-statsig---unified-experimentation-feature-flags-and-analytics">6. Statsig - Unified Experimentation, Feature Flags, and Analytics<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#6-statsig---unified-experimentation-feature-flags-and-analytics" class="hash-link" aria-label="Direct link to 6. Statsig - Unified Experimentation, Feature Flags, and Analytics" title="Direct link to 6. Statsig - Unified Experimentation, Feature Flags, and Analytics" translate="no">​</a></h2>
<p><a href="https://www.statsig.com/" target="_blank" rel="noopener noreferrer" class="">Statsig</a> (now part of <a href="https://openai.com/" target="_blank" rel="noopener noreferrer" class="">OpenAI</a>) is for the analytics-obsessed: tons of flags, tons of experiments, tons of data. Plus, it offers both hosted and “warehouse-native” deployments, so you can choose where your data lives. In September 2025, OpenAI announced a $1.1B acquisition of Statsig, with Statsig operating under OpenAI’s Applications division, tracking insights with the intensity of a cat watching a laser pointer.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-like-statsig">Why teams like Statsig<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-like-statsig" class="hash-link" aria-label="Direct link to Why teams like Statsig" title="Direct link to Why teams like Statsig" translate="no">​</a></h3>
<ul>
<li class="">Unlimited free feature flags across tiers</li>
<li class="">Built-in A/B and multivariate testing, guardrail metrics, dashboards</li>
<li class="">No per-seat pricing – pricing is based on events &amp; session replays, with unlimited seats and flags</li>
<li class="">Warehouse Native mode: run experiment analysis directly in your data warehouse (Snowflake, BigQuery, Redshift, Databricks, etc.)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-5">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-5" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Free: Unlimited flags, 2M monthly events, 50k session replays, basic analytics</li>
<li class="">Paid plans: Usage‑based pricing that scales with events, premium features, and support</li>
</ul>
<p><strong>Best for you if:</strong> you want a deeply integrated experimentation + feature management solution and advanced analytics out of the box.</p>
<p><strong>Less ideal if:</strong> you’re wary of long-term dependence on a vendor now embedded within a large AI company.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-growthbook----open-source--warehouse-native-experiments">7. GrowthBook -  Open-Source &amp; Warehouse-Native Experiments<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#7-growthbook----open-source--warehouse-native-experiments" class="hash-link" aria-label="Direct link to 7. GrowthBook -  Open-Source &amp; Warehouse-Native Experiments" title="Direct link to 7. GrowthBook -  Open-Source &amp; Warehouse-Native Experiments" translate="no">​</a></h2>
<p><a href="https://www.growthbook.io/" target="_blank" rel="noopener noreferrer" class="">GrowthBook</a> is open-source and “warehouse-native” built for teams that want to keep their experiment data where they already keep everything else. If thinking in SQL comes as naturally to you as napping does to a cat, GrowthBook will feel like a perfect fit.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-like-growthbook">Why teams like GrowthBook<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-like-growthbook" class="hash-link" aria-label="Direct link to Why teams like GrowthBook" title="Direct link to Why teams like GrowthBook" translate="no">​</a></h3>
<ul>
<li class="">Open-source core with self-hosted and cloud options</li>
<li class="">Experimentation suite: A/B, multivariate, and retroactive analysis</li>
<li class="">Warehouse-native: plug directly into Snowflake, BigQuery, Redshift, and more</li>
<li class="">Visual experiment editor and results dashboard</li>
<li class="">OpenFeature providers available for multiple languages</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-6">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-6" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Open-source: Free forever, unlimited flags and experiments, self‑hosted</li>
<li class="">Cloud: Free tier with usage limits, paid plans for higher traffic, SSO, and enterprise features</li>
<li class="">Custom enterprise plans available for strict compliance and SLAs</li>
</ul>
<p><strong>Best for you if:</strong> you want to keep all experiment data in your own warehouse, value open‑source control, and need robust statistical analysis.</p>
<p><strong>Less ideal if:</strong> you just want a lightweight flagging tool without experimentation, or you prefer a pure plug‑and‑play SaaS solution.</p>
<p>Similar to other open-source feature flag tools, If you self-host the open-source version, you’ll miss features like SSO/SAML, Prerequisite Flags, and Advanced RBAC Permissioning.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-devcycle---openfeature-native-edge-first-feature-management">8. DevCycle - OpenFeature-Native, Edge-First Feature Management<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#8-devcycle---openfeature-native-edge-first-feature-management" class="hash-link" aria-label="Direct link to 8. DevCycle - OpenFeature-Native, Edge-First Feature Management" title="Direct link to 8. DevCycle - OpenFeature-Native, Edge-First Feature Management" translate="no">​</a></h2>
<p><a href="https://devcycle.com/" target="_blank" rel="noopener noreferrer" class="">DevCycle</a> is built for developers who live and breathe automation, GitHub, and Jira. If your pipeline chain is longer than a cat’s list of hiding spots, DevCycle has a flag for every step.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-teams-like-devcycle">Why teams like DevCycle<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#why-teams-like-devcycle" class="hash-link" aria-label="Direct link to Why teams like DevCycle" title="Direct link to Why teams like DevCycle" translate="no">​</a></h3>
<ul>
<li class="">OpenFeature-native platform with first-class OpenFeature integrations</li>
<li class="">Integrates easily with GitHub, Jira, Datadog, and more</li>
<li class="">Edge Flags &amp; EdgeDB for low-latency, globally replicated flag decisions</li>
<li class="">Supports automated workflows for CI/CD pipelines</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pricing-7">Pricing<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#pricing-7" class="hash-link" aria-label="Direct link to Pricing" title="Direct link to Pricing" translate="no">​</a></h3>
<ul>
<li class="">Free: unlimited seats, up to 1,000 client-side MAUs, ideal for small projects or trials</li>
<li class="">Paid plans: usage‑based pricing scales with flag evaluations, includes advanced features like SSO, custom roles, and priority support</li>
<li class="">Enterprise options available with SLAs, SOC2 compliance, and dedicated onboarding</li>
</ul>
<p><strong>Best for you if:</strong> your team is heavily invested in modern DevOps tooling and wants feature flags that plug directly into automated pipelines.</p>
<p><strong>Less ideal if:</strong> you want open-source server components (DevCycle focuses on OpenFeature + open SDKs rather than fully OSS backend).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="quick-comparison-table-launchdarkly-alternatives-at-a-glance">Quick Comparison Table (LaunchDarkly Alternatives at a Glance)<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#quick-comparison-table-launchdarkly-alternatives-at-a-glance" class="hash-link" aria-label="Direct link to Quick Comparison Table (LaunchDarkly Alternatives at a Glance)" title="Direct link to Quick Comparison Table (LaunchDarkly Alternatives at a Glance)" translate="no">​</a></h2>
<p>Here’s how the top LaunchDarkly alternatives compare across pricing, experimentation, and ecosystem. This table is the best place to start if you want to compare LaunchDarkly competitors.</p>
<table><thead><tr><th>Tool</th><th>Free Tier <br> Highlights</th><th>Pricing Model &amp; Key Limits</th><th>Experimentation <br>/Analytics <br> Built-in?</th><th>Integrations <br> &amp; Ecosystem</th></tr></thead><tbody><tr><td>ConfigCat</td><td>Free: 10 flags, 2 products, 2 environments, unlimited team members, 5M config downloads/mo</td><td>Flat usage-based (no per-seat/MAU fees), scales with config downloads</td><td>Light (requires external analytics)</td><td>GitHub, Slack, Azure DevOps, Jira, Webhooks</td></tr><tr><td>Flagsmith</td><td>Free: unlimited flags/environments, 1 user, 50k req/mo</td><td>Paid: starts $45/mo for 1M requests &amp; team features</td><td>Supports A/B and multivariate testing</td><td>Segment, Datadog, Jira, Amplitude</td></tr><tr><td>Split (Harness FME)</td><td>Free trial available</td><td>Per-user pricing (min 10 users) from $33/user/mo</td><td>Advanced experimentation &amp; impact detection</td><td>40+ integrations incl. Slack, Jira, Datadog</td></tr><tr><td>Unleash</td><td>Free: core features for 2 environments (self-host)</td><td>Managed plans: usage-based pricing for more envs, SSO, support</td><td>No analytics, but strong rollout strategies</td><td>Webhooks, custom integrations</td></tr><tr><td>PostHog</td><td>Free OSS: unlimited flags (no A/B)</td><td>Cloud: pay-as-you-go after 1M API requests</td><td>Analytics, session replay, surveys</td><td>Integrates with data warehouses &amp; pipelines</td></tr><tr><td>Statsig</td><td>Free: unlimited flags + 2M events/mo</td><td>Paid: scales by events/analytics usage</td><td>Full experimentation + dashboards</td><td>Snowflake, BigQuery, Redshift</td></tr><tr><td>GrowthBook</td><td>Free: unlimited flags &amp; experiments (self-host)</td><td>Cloud: free tier with limits, paid for scale/compliance</td><td>A/B, multivariate, retroactive analysis</td><td>Connects directly to data warehouses</td></tr><tr><td>DevCycle</td><td>Free: limited flags/users</td><td>Paid: usage-based pricing</td><td>Limited experimentation (flag focus)</td><td>GitHub, Jira, Datadog</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="final-thoughts">Final Thoughts<a href="https://configcat.com/blog/top-eight-launchdarkly-alternatives/#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Whichever LaunchDarkly alternative you choose, the right feature flag tool will help you ship faster and sleep better. At ConfigCat, we believe in transparent pricing, zero data collection, and making life easier for development teams. Plus, we’ll never charge you extra for inviting more teammates.</p>
<p>If you made it this far, you deserve a break! Go pet a cat, take a walk, or try toggling a feature on (or off) just for fun. If you’re ready to see how simple (and fun) feature flagging can be, give <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">ConfigCat’s Forever Free plan</a> a try and let your next release be purr-fectly smooth.</p>
<p>You can stay up-to-date with ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>, and <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>.</p>]]></content:encoded>
            <category>alternatives</category>
            <category>LaunchDarkly</category>
            <category>ConfigCat</category>
            <category>feature flags</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags in Flutter: Smarter Releases with ConfigCat]]></title>
            <link>https://configcat.com/blog/best-practices-in-dart-flutter/</link>
            <guid>https://configcat.com/blog/best-practices-in-dart-flutter/</guid>
            <pubDate>Thu, 27 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to use feature flags in Flutter with ConfigCat to enable safer rollouts, A/B testing, and remote feature management in your mobile app.]]></description>
            <content:encoded><![CDATA[<p>Releasing new features in a mobile app can feel like walking a tightrope, especially when updates require going through lengthy App Store and Google Play review processes, and users still need to download the new build. That's where feature flags come in. They are software development tools that give developers the power to toggle features remotely, test new functionality safely, and control rollouts without shipping a new app version.</p>
<p>This guide shows you how to use feature flags in <a href="https://flutter.dev/" target="_blank" rel="noopener noreferrer" class="">Flutter (Dart)</a> with <a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a>, focusing on best practices, manual polling, offline support, and real-world examples.</p>
<img alt="Best practices in Dart (Flutter) cover" src="https://configcat.com/blog/assets/best-practices-in-dart-flutter/why-configcat-belongs-in-your-app-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-use-feature-flags-in-flutter-apps">Why Use Feature Flags in Flutter Apps?<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#why-use-feature-flags-in-flutter-apps" class="hash-link" aria-label="Direct link to Why Use Feature Flags in Flutter Apps?" title="Direct link to Why Use Feature Flags in Flutter Apps?" translate="no">​</a></h2>
<p>Feature flags (also called <em>feature toggles</em>) are a best practice for Flutter app development. They help you:</p>
<ul>
<li class=""><strong>Test in production safely</strong> by <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">targeting specific users</a> while others see the existing version.</li>
<li class=""><strong>Turn off features remotely</strong>, without resubmitting your app for review.</li>
<li class=""><strong>Roll out features gradually</strong> to monitor performance and stability.</li>
<li class=""><strong>Decouple release from deployment</strong>, giving your team more control over what users see.</li>
</ul>
<p>These benefits are especially useful in mobile development, where deployment cycles can be slow and risky.</p>
<p>I'm sure you can agree that these benefits are worthwhile, especially when working with an evolving product.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-configcat-fetches-flags-polling-modes-explained">How ConfigCat Fetches Flags: Polling Modes Explained<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#how-configcat-fetches-flags-polling-modes-explained" class="hash-link" aria-label="Direct link to How ConfigCat Fetches Flags: Polling Modes Explained" title="Direct link to How ConfigCat Fetches Flags: Polling Modes Explained" translate="no">​</a></h2>
<p>In ConfigCat, <strong>polling</strong> refers to how your app fetches the latest feature flag values from ConfigCat's servers.</p>
<p>There are three main polling modes:</p>
<ul>
<li class=""><a href="https://configcat.com/docs/sdk-reference/dart/#auto-polling-default" target="_blank" rel="noopener noreferrer" class="">Auto Polling</a>: Fetches flags periodically in the background.</li>
<li class=""><a href="https://configcat.com/docs/sdk-reference/dart/#lazy-loading" target="_blank" rel="noopener noreferrer" class="">Lazy Loading</a>: Fetches only when you ask for a flag, with optional caching.</li>
<li class=""><a href="https://configcat.com/docs/sdk-reference/dart/#manual-polling" target="_blank" rel="noopener noreferrer" class="">Manual Polling</a>: You control exactly when the flags are fetched.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-mobile-developers-prefer-manual-polling">Why Mobile Developers Prefer Manual Polling<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#why-mobile-developers-prefer-manual-polling" class="hash-link" aria-label="Direct link to Why Mobile Developers Prefer Manual Polling" title="Direct link to Why Mobile Developers Prefer Manual Polling" translate="no">​</a></h2>
<p>Manual polling gives mobile apps <strong>full control</strong> over when network calls are made. This is important because:</p>
<ul>
<li class="">Mobile apps have startup performance concerns</li>
<li class="">You don't always want to fetch data unless necessary (e.g., poor connectivity)</li>
<li class="">You want to minimize battery and network usage</li>
</ul>
<p>Let's now look at an example of how to implement Manual Polling.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="setting-up-configcat-with-manual-polling-in-flutter">Setting up ConfigCat with Manual Polling in Flutter<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#setting-up-configcat-with-manual-polling-in-flutter" class="hash-link" aria-label="Direct link to Setting up ConfigCat with Manual Polling in Flutter" title="Direct link to Setting up ConfigCat with Manual Polling in Flutter" translate="no">​</a></h2>
<p>Here's a realistic example: you're building a weather app, and you've developed a new radar map feature that you want to release only to beta testers. Here's how you can do it:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-add-dependencies">Step 1: Add Dependencies<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#step-1-add-dependencies" class="hash-link" aria-label="Direct link to Step 1: Add Dependencies" title="Direct link to Step 1: Add Dependencies" translate="no">​</a></h3>
<p>The first is the ConfigCat client dependency. I'll use <code>shared_preferences</code> for caching (explained soon).</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">pubspec.yaml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token key atrule">dependencies</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">configcat_client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ^2.1.0</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">shared_preferences</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ^2.2.0</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-initialize-configcat-with-manual-polling">Step 2: Initialize ConfigCat with Manual Polling<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#step-2-initialize-configcat-with-manual-polling" class="hash-link" aria-label="Direct link to Step 2: Initialize ConfigCat with Manual Polling" title="Direct link to Step 2: Initialize ConfigCat with Manual Polling" translate="no">​</a></h3>
<div class="language-dart codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dart codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token string-literal string" style="color:rgb(195, 232, 141)">'package:configcat_client/configcat_client.dart'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">final</span><span class="token plain"> client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token keyword" style="font-style:italic">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string-literal string" style="color:rgb(195, 232, 141)">'YOUR-CONFIGCAT-SDK-KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">//FOUND IN YOUR CONFIGCAT ACCOUNT</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatOptions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> pollMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">PollMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">manualPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-fetch-flags-using-forcerefresh-at-app-startup">Step 3: Fetch Flags Using <code>forceRefresh()</code> at App Startup<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#step-3-fetch-flags-using-forcerefresh-at-app-startup" class="hash-link" aria-label="Direct link to step-3-fetch-flags-using-forcerefresh-at-app-startup" title="Direct link to step-3-fetch-flags-using-forcerefresh-at-app-startup" translate="no">​</a></h3>
<p>So far, I've set up manual polling, but I also need to tell ConfigCat to fetch the latest flags when the app launches by calling the <code>forceRefresh()</code> method on the client.</p>
<div class="language-dart codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dart codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">forceRefresh</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>Then, use the flag value:</p>
<div class="language-dart codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dart codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">bool isRadarMapEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token string-literal string" style="color:rgb(195, 232, 141)">'radar_map_feature_enabled'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isRadarMapEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Show new feature</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Fallback UI</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="making-feature-flags-persistent-in-flutter-using-sharedpreferences">Making Feature Flags Persistent in Flutter Using SharedPreferences<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#making-feature-flags-persistent-in-flutter-using-sharedpreferences" class="hash-link" aria-label="Direct link to Making Feature Flags Persistent in Flutter Using SharedPreferences" title="Direct link to Making Feature Flags Persistent in Flutter Using SharedPreferences" translate="no">​</a></h2>
<p>By default, ConfigCat stores flag values in memory. That means values are lost when the app restarts. This isn't ideal for mobile apps, which are frequently closed and reopened.</p>
<p>Let's fix that with <code>SharedPreferences</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-a-simple-cache-helper">Step 1: Create a Simple Cache Helper<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#step-1-create-a-simple-cache-helper" class="hash-link" aria-label="Direct link to Step 1: Create a Simple Cache Helper" title="Direct link to Step 1: Create a Simple Cache Helper" translate="no">​</a></h3>
<div class="language-dart codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dart codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token string-literal string" style="color:rgb(195, 232, 141)">'package:shared_preferences/shared_preferences.dart'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatCache</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">String</span><span class="token plain"> _cacheKey </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-literal string" style="color:rgb(195, 232, 141)">'configcat_cached_flags'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Future</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generics keyword" style="font-style:italic">void</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">save</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">String</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">final</span><span class="token plain"> prefs </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">SharedPreferences</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getInstance</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> prefs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">setString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">_cacheKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Future</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generics class-name" style="color:rgb(255, 203, 107)">String</span><span class="token generics operator" style="color:rgb(137, 221, 255)">?</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">load</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">final</span><span class="token plain"> prefs </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">SharedPreferences</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getInstance</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> prefs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">_cacheKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-save-config-after-a-refresh">Step 2: Save Config After a Refresh<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#step-2-save-config-after-a-refresh" class="hash-link" aria-label="Direct link to Step 2: Save Config After a Refresh" title="Direct link to Step 2: Save Config After a Refresh" translate="no">​</a></h3>
<div class="language-dart codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dart codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">forceRefresh</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">final</span><span class="token plain"> allFlags </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getAllValues</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">save</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">jsonEncode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">allFlags</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-use-cached-values-when-offline">Step 3: Use Cached Values When Offline<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#step-3-use-cached-values-when-offline" class="hash-link" aria-label="Direct link to Step 3: Use Cached Values When Offline" title="Direct link to Step 3: Use Cached Values When Offline" translate="no">​</a></h3>
<div class="language-dart codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dart codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">final</span><span class="token plain"> cachedString </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">load</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">cachedString </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">final</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Map</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generics class-name" style="color:rgb(255, 203, 107)">String</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token generics"> </span><span class="token generics keyword" style="font-style:italic">dynamic</span><span class="token generics punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> flags </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">jsonDecode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">cachedString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use your flags here</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>This allows you to serve the latest cached flag values when the user loses connectivity, making your app's behavior persistent across sessions.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/best-practices-in-dart-flutter/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Using feature flags in your Flutter apps may seem like a luxury, but it's actually a <strong>best practice</strong>. With review times taking longer and users becoming frustrated by frequent updates, <strong>it's essential to have control over your application</strong>.</p>
<p>To really get the most out of feature flags, you need a solution that’s reliable, flexible, mobile-optimized, and easy to plug into your tech stack. That’s where <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> comes in.</p>
<p>By using <strong>ConfigCat</strong> feature flags, you get:</p>
<ul>
<li class="">Remote control over what your users see</li>
<li class="">Smart rollout strategies</li>
<li class="">Detailed user targeting</li>
</ul>
<p>Whether you're testing in production, experimenting with A/B tests, or gradually rolling out risky features, ConfigCat makes integrating feature flag management into your mobile workflow seamless, giving you the tools to stay agile and safe. Apart from Dart, ConfigCat supports many <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">programming languages, frameworks, and platforms</a>.</p>
<p>Try it out today by <a href="https://app.configcat.com/signup" target="_blank" rel="noopener noreferrer" class="">signing up</a> for a <a href="https://configcat.com/pricing" target="_blank" rel="noopener noreferrer" class="">forever free account</a>, and dive into the official <a href="https://configcat.com/docs/sdk-reference/dart" target="_blank" rel="noopener noreferrer" class="">Flutter SDK documentation</a>.</p>
<p>Want to stay updated on the latest feature flag tips, Flutter integration tutorials, and remote config strategies? Connect with ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>Dart</category>
            <category>Flutter</category>
            <category>SDK</category>
            <category>how to</category>
            <category>best practices</category>
        </item>
        <item>
            <title><![CDATA[How to Integrate Feature Flags in NestJS]]></title>
            <link>https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/</link>
            <guid>https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/</guid>
            <pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A step-by-step guide to using ConfigCat feature flags in a NestJS application to introduce a new feature smoothly.]]></description>
            <content:encoded><![CDATA[<p>Software development can be challenging, but deploying and managing new features shouldn't be. With feature flags, you can rest assured that your updates and new features are delivered safely with minimal risk. In this guide, I'll show you how to integrate a feature flag into a NestJS application.</p>
<img alt="How to use feature flags in NestJS cover" src="https://configcat.com/blog/assets/feature-flags-in-nestjs/how-to-use-feature-flags-in-nestjs-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<p>Before we dive in, let's take a moment to understand how feature flags work.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-do-feature-flags-work">How Do Feature Flags Work?<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#how-do-feature-flags-work" class="hash-link" aria-label="Direct link to How Do Feature Flags Work?" title="Direct link to How Do Feature Flags Work?" translate="no">​</a></h2>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer" class="">Feature flags</a>, sometimes called feature toggles or feature switches, are mechanisms used to conditionally hide or display features in an application. A feature flag typically holds a Boolean value that your code can use to enable or disable a feature. Feature flag evaluation can also take into account an evaluation context, such as user role or request data, to enable <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">user targeting</a>.</p>
<p>With feature flags, developers can include an unfinished new feature in the codebase and then toggle it on with just a click.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>To learn more about feature flags and how they can benefit your development workflow, <a href="https://configcat.com/feature-flag-framework-explained/" target="_blank" rel="noopener noreferrer" class="">click here</a>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sample-app">Sample App<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#sample-app" class="hash-link" aria-label="Direct link to Sample App" title="Direct link to Sample App" translate="no">​</a></h2>
<p>To show you a practical example of feature flags in action, I've created a <a href="https://github.com/configcat-labs/feature-flags-in-nestjs-sample" target="_blank" rel="noopener noreferrer" class="">demo auto dealership website</a> using <a href="https://nestjs.com/" target="_blank" rel="noopener noreferrer" class="">NestJS</a>. The new feature is a fuel mileage calculator to be displayed under the banner on the home page. To put this feature behind a flag, I'll use <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> feature flag system. ConfigCat provides a <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">wide range of SDKs</a> and <a href="https://configcat.com/docs/integrations/overview/" target="_blank" rel="noopener noreferrer" class="">integrations</a>, making it easy to effectively manage your own feature flags across your tech stack.</p>
<p>To follow along, check if you have the following:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<ul>
<li class="">A code editor, e.g., <a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer" class="">Visual Studio Code</a>.</li>
<li class=""><a href="https://nodejs.org/en" target="_blank" rel="noopener noreferrer" class="">Node.js</a> version 22 or higher installed on your machine.</li>
<li class="">Basic knowledge of <a href="https://nestjs.com/" target="_blank" rel="noopener noreferrer" class="">NestJS</a> and JavaScript.</li>
<li class="">A <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">ConfigCat account</a> to create and manage the feature flag.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sample-app-setup">Sample App Setup<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#sample-app-setup" class="hash-link" aria-label="Direct link to Sample App Setup" title="Direct link to Sample App Setup" translate="no">​</a></h2>
<ol>
<li class="">
<p>Create a new directory for the project. You can name it <code>feature-flags-in-nestjs-sample</code>.</p>
</li>
<li class="">
<p>Install the <a href="https://docs.nestjs.com/cli/overview" target="_blank" rel="noopener noreferrer" class="">Nest CLI</a> tool, and create a new NestJS project with the following commands:</p>
</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm i -g @nestjs/cli</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">nest new feature-flags-in-nestjs-sample</span><br></div></code></pre></div></div>
<p>When prompted, select <strong>npm</strong> as the package manager and give it a moment to complete.</p>
<ol start="3">
<li class="">Launch the NestJS app and access it in your browser at <a href="http://localhost:3000/" target="_blank" rel="noopener noreferrer" class="">http://localhost:3000/</a>. You should see a "Hello World!" message displayed.</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm run start:dev</span><br></div></code></pre></div></div>
<ol start="4">
<li class="">Lets use the <a href="https://handlebarsjs.com/" target="_blank" rel="noopener noreferrer" class="">Handlebars</a> templating engine to build the frontend. Install it with the following command:</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install --save hbs</span><br></div></code></pre></div></div>
<ol start="5">
<li class="">To configure the NestJS app to use the Handlebars templating engine, update the <code>src/main.ts</code> file as shown below:</li>
</ol>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">src/main.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">NestFactory</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@nestjs/core'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">NestExpressApplication</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@nestjs/platform-express'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> join </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'path'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">AppModule</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./app.module'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">bootstrap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> app </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token maybe-class-name">NestFactory</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">create</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">NestExpressApplication</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">AppModule</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">useStaticAssets</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">join</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'../'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'public'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">setBaseViewsDir</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">join</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'../'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'views'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">setViewEngine</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'hbs'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">listen</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">PORT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">??</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Application is running on: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation keyword control-flow" style="font-style:italic">await</span><span class="token template-string interpolation"> app</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation method function property-access" style="color:rgb(130, 170, 255)">getUrl</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">bootstrap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<ol start="6">
<li class="">
<p>Create a new folder called <strong>views</strong> in the root directory, then create an <code>index.hbs</code> file inside it for the home page, using the content from <a href="https://github.com/configcat-labs/feature-flags-in-nestjs-sample/blob/master/views/index.hbs" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
</li>
<li class="">
<p>Update the <code>src/app.controller.ts</code> file as shown below. This code instructs the app to call the App Service (<code>src/app.service.ts</code>) to get the view name for rendering. Later, we’ll add some future feature flag logic to it.</p>
</li>
</ol>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">src/app.controller.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Req </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@nestjs/common'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> AppService </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./app.service'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Request </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'express'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">Controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AppController</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">constructor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> appService</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> AppService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> configCatService</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> ConfigCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">Get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'/*'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">root</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">Req</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> req</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">Res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> res</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> viewName </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">appService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getViewName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">req</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">viewName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<ol start="8">
<li class="">In the <code>src/app.service.ts</code> file, I've added a URL to view map. The <code>getViewName</code> function in the previous step uses the map to get the view based on the request URL.</li>
</ol>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">src/app.service.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Injectable </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@nestjs/common'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Request </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'express'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">Injectable</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AppService</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> urlToViewMap</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Record</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string-property property">'/'</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'index'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getViewName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">req</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">urlToViewMap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">req</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">||</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'not-found'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>Launch the app and go to <a href="http://localhost:3000/" target="_blank" rel="noopener noreferrer" class="">http://localhost:3000/</a> to view the home page. You'll see the text <em>Fuel Per Mileage Calculator is coming soon. Stay tuned!</em> at the bottom.</p>
<img alt="Sample app with feature and text" src="https://configcat.com/blog/assets/feature-flags-in-nestjs/sample-app-with-feature-and-text_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<p>Let's use a ConfigCat feature flag to display the mileage calculator when the flag is enabled and show the text when it is disabled.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="setup-and-integrate-the-feature-flag">Setup and Integrate the Feature Flag<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#setup-and-integrate-the-feature-flag" class="hash-link" aria-label="Direct link to Setup and Integrate the Feature Flag" title="Direct link to Setup and Integrate the Feature Flag" translate="no">​</a></h2>
<ol>
<li class="">In your <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a>, create a feature flag with the following feature name and key:</li>
</ol>
<table><thead><tr><th>Field</th><th>Value</th></tr></thead><tbody><tr><td><strong>name</strong></td><td>Mileage Calculator Feature</td></tr><tr><td><strong>key</strong></td><td>mileageCalculatorFeature</td></tr></tbody></table>
<ol start="2">
<li class="">NestJS is a <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Web_frameworks" target="_blank" rel="noopener noreferrer" class="">server-side framework</a>, so I'll install <a href="https://configcat.com/docs/sdk-reference/js/node/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's Node SDK</a>:</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm i @configcat/sdk</span><br></div></code></pre></div></div>
<ol start="3">
<li class="">I'll create a custom ConfigCat feature service that I can import and use in other files. In the <code>src</code> directory, create a <code>configcat.service.ts</code> file with the following content:</li>
</ol>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">src/configcat.service.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Injectable</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@nestjs/common'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports operator" style="color:rgb(137, 221, 255)">*</span><span class="token imports"> </span><span class="token imports keyword module" style="font-style:italic">as</span><span class="token imports"> configcat</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@configcat/sdk'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> type </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token maybe-class-name">IConfigCatClient</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@configcat/sdk'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">@</span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">Injectable</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatService</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> readonly configCatClient</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">IConfigCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">constructor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">configCatClient</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'YOUR-CONFIGCAT-SDK-KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token literal-property property">defaultValue</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">Promise</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">boolean</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">configCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> defaultValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<ol start="4">
<li class="">I'll update the <code>src/app.controller.ts</code> file. I'll use the feature service to query the value of the feature flag and then pass it to the view.</li>
</ol>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">src/app.controller.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Controller</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">Get</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">Res</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">Req</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@nestjs/common'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">AppService</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./app.service'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> type </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token maybe-class-name">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token maybe-class-name">Request</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'express'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatService</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./configcat.service'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">@</span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">Controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AppController</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">constructor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token parameter keyword" style="font-style:italic">private</span><span class="token parameter"> readonly appService</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">AppService</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token parameter">    </span><span class="token parameter keyword" style="font-style:italic">private</span><span class="token parameter"> readonly configCatService</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">ConfigCatService</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  @</span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">Get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'/*'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">root</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">@</span><span class="token parameter function maybe-class-name" style="color:rgb(130, 170, 255)">Req</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token parameter"> req</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">Request</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> @</span><span class="token parameter function maybe-class-name" style="color:rgb(130, 170, 255)">Res</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token parameter"> res</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> viewName </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">appService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getViewName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">req</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get the value of the feature flag</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> isMileageCalculatorFeatureEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">configCatService</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'mileageCalculatorFeature'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">viewName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      isMileageCalculatorFeatureEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Pass the value to the view</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<ol start="5">
<li class="">In the <code>index.hbs</code> file, I'll use the <code>isMileageCalculatorFeatureEnabled</code> variable passed from the controller with conditional logic to render the mileage calculator feature, as shown below:</li>
</ol>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_OeMC">index.hbs</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">class</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">'</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">container</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">'</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> {{#if isMileageCalculatorFeatureEnabled }}</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">&lt;!-- Render the mileage calculator feature --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">class</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">'</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">mileage-calculator</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">'</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h2</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain">Fuel Per Mileage Calculator</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h2</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">class</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">'</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">calculator</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">'</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">&lt;!-- HTML code for the calculator --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> {{else}}</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">&lt;!-- Else, render the following text --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> Fuel Per Mileage Calculator is coming soon. Stay tuned!</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> {{/if}}</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="app-demo">App Demo<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#app-demo" class="hash-link" aria-label="Direct link to App Demo" title="Direct link to App Demo" translate="no">​</a></h2>
<ol>
<li class="">When the feature flag is on in the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a>, the home page should look like this:</li>
</ol>
<img alt="Sample app - flag on" src="https://configcat.com/blog/assets/feature-flags-in-nestjs/sample-app_192dpi.png" width="1366" height="768" decoding="async" loading="lazy">
<ol start="2">
<li class="">When the feature flag is switched off, the following text will be displayed on the home page:</li>
</ol>
<img alt="Sample app - flag off" src="https://configcat.com/blog/assets/feature-flags-in-nestjs/sample-app-flag-off_192dpi.png" width="1366" height="514" decoding="async" loading="lazy">
<p>By default, the ConfigCat client SDK uses AutoPoll to check the status of the feature flag every 60 seconds, eliminating the need to restart the app. You can also adjust this interval to your choosing. Learn more about it <a href="https://configcat.com/docs/sdk-reference/node/#polling-modes" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://configcat.com/blog/how-to-integrate-feature-flags-in-nestjs/#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>In this guide, we covered how to integrate feature flags into a NestJS application using <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's feature management service</a>.</p>
<p>Feature flag services like ConfigCat make it easy to manage and release new features from a <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">central dashboard</a>, allowing you to toggle features on and off without redeploying your app.</p>
<p>Beyond NestJS, ConfigCat provides a <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">wide range of SDKs</a> and <a href="https://configcat.com/integrations/" target="_blank" rel="noopener noreferrer" class="">integrations</a> to integrate feature flags across your technology stack. To learn more, check out <a href="https://configcat.com/docs" target="_blank" rel="noopener noreferrer" class="">ConfigCat's official documentation</a>.</p>
<p>For more posts like this and the latest updates, follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>NestJS</category>
            <category>feature flags</category>
            <category>server side</category>
            <category>feature management</category>
            <category>JavaScript</category>
            <category>how to</category>
        </item>
        <item>
            <title><![CDATA[How to Manage Feature Flags with ConfigCat's MCP Server]]></title>
            <link>https://configcat.com/blog/mcp-server-feature-flags/</link>
            <guid>https://configcat.com/blog/mcp-server-feature-flags/</guid>
            <pubDate>Wed, 22 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to manage your feature flags via natural-language prompts with ConfigCat's Model Context Protocol (MCP) server.]]></description>
            <content:encoded><![CDATA[<p>In this guide, you’ll learn how to connect your AI client to <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> so you can <strong>list, create, and target feature flags</strong> using natural language with ConfigCat’s MCP server.</p>
<img alt="Update feature flag with ConfigCat MCP server" src="https://configcat.com/blog/assets/mcp-server-feature-flags/mcp-server-feature-flags-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://configcat.com/blog/mcp-server-feature-flags/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">ConfigCat account</a> - If you don’t have one yet, <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">sign up here for free</a></li>
<li class=""><a href="https://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">Node.js</a> version 16 or higher installed</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-model-context-protocol-mcp">What is Model Context Protocol (MCP)?<a href="https://configcat.com/blog/mcp-server-feature-flags/#what-is-model-context-protocol-mcp" class="hash-link" aria-label="Direct link to What is Model Context Protocol (MCP)?" title="Direct link to What is Model Context Protocol (MCP)?" translate="no">​</a></h2>
<p><a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol (MCP)</a> is an open-source standard for connecting AI applications to external systems. It lets you interact with tools and services using natural language.</p>
<p><a href="https://github.com/configcat/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat's MCP server</a> provides access to <a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's public management API</a> for feature flag and configuration management. It also enables your code editor to understand your feature flags, integrate the appropriate ConfigCat SDK into your project or even create new feature flags directly in your codebase.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-public-api-credentials">Creating Public API credentials<a href="https://configcat.com/blog/mcp-server-feature-flags/#creating-public-api-credentials" class="hash-link" aria-label="Direct link to Creating Public API credentials" title="Direct link to Creating Public API credentials" translate="no">​</a></h2>
<p>The MCP server needs a ConfigCat Public API credential to access the <a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's public management API</a> and perform the same actions available in the ConfigCat dashboard (like managing feature flags, organizations, configs, targeting rules, segments and audit logs, etc.)</p>
<p>You can create this credential on the <a href="https://app.configcat.com/my-account/public-api-credentials" target="_blank" rel="noopener noreferrer" class="">Public API credentials management page</a>.
The MCP server will use this credential and will have the same permissions.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-mcp-server">Installing MCP Server<a href="https://configcat.com/blog/mcp-server-feature-flags/#installing-mcp-server" class="hash-link" aria-label="Direct link to Installing MCP Server" title="Direct link to Installing MCP Server" translate="no">​</a></h2>
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">Cursor</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Visual Studio Code</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Claude Desktop</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><ol>
<li class="">Install <a href="https://cursor.com/" target="_blank" rel="noopener noreferrer" class="">Cursor</a></li>
<li class="">Open <strong>Preferences</strong> → <strong>Cursor Settings</strong> → <strong>MCP &amp; Integrations</strong></li>
<li class="">Click <strong>Add Custom MCP</strong></li>
<li class="">Add (or merge) the snippet below into your JSON settings:</li>
</ol><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"mcpServers"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"ConfigCat"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"command"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"npx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"-y"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/mcp-server"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"env"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_USER"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_USER"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_PASS"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><ol start="5">
<li class=""><strong>Save</strong> – the server will start on demand.</li>
<li class="">You can start writing prompts into Cursor's AI panel.</li>
</ol></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><ol>
<li class="">Install <a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer" class="">VS Code</a> and <a href="https://code.visualstudio.com/docs/copilot/setup" target="_blank" rel="noopener noreferrer" class="">GitHub Copilot</a></li>
<li class="">Create a <code>.vscode/mcp.json</code> file in your project root with the following content:</li>
</ol><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"servers"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"ConfigCat"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"command"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"npx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"-y"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/mcp-server"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"env"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_USER"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_USER"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_PASS"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><ol start="3">
<li class="">Save the settings file. The MCP server should now be available in VS Code.</li>
<li class="">You can start writing prompts into VS Code's AI panel.</li>
</ol></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><ol>
<li class="">Install <a href="https://claude.ai/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a></li>
<li class="">Open <strong>Settings</strong> → <strong>Developer</strong></li>
<li class="">Click <strong>Edit Config</strong></li>
<li class="">In <code>claude_desktop_config.json</code> add:</li>
</ol><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"mcpServers"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"ConfigCat"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"command"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"npx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"-y"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"@configcat/mcp-server"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"env"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_USER"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_USER"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"CONFIGCAT_API_PASS"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><ol start="5">
<li class=""><strong>Save</strong> &amp; restart Claude Desktop.</li>
</ol></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Replace <code>YOUR_API_USER</code> and <code>YOUR_API_PASSWORD</code> environment variables with your <a href="https://app.configcat.com/my-account/public-api-credentials" target="_blank" rel="noopener noreferrer" class="">ConfigCat Public API credentials</a>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="managing-feature-flags-with-mcp-server">Managing Feature Flags with MCP Server<a href="https://configcat.com/blog/mcp-server-feature-flags/#managing-feature-flags-with-mcp-server" class="hash-link" aria-label="Direct link to Managing Feature Flags with MCP Server" title="Direct link to Managing Feature Flags with MCP Server" translate="no">​</a></h2>
<p>Let's try asking the agent to <strong>list all flags</strong> using the following prompt:</p>
<div class="qa-row qa-row--human"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Prompt:</p><p class="qa-row__text"></p><p>List my feature flags</p><p></p></div></div>
<p>Model responses are non-deterministic, so your response might differ from the following, but it should look similar to this:</p>
<div class="qa-row qa-row--ai"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Answer:</p><p class="qa-row__text"></p><p>I'll help you list your feature flags.  Let me start by getting your organizations and products.<br></p><br><p><strong>Organization:</strong> Test Organization<br>
<strong>Product:</strong> Test Product<br>
<strong>Config:</strong> Main Config<br></p><br><strong>Feature Flags:</strong><br><ol>
<li class=""><strong>My First Feature Flag</strong><br>
<strong>Key:</strong> <code>isMyFirstFeatureEnabled</code><br>
<strong>Type:</strong> Boolean<br>
<strong>Description:</strong> This is your first feature flag. Automatically created to help you get started and to play around with.<br></li>
</ol><strong>Environments:</strong><br><ul>
<li class="">
<strong>Test Environment</strong>
<br>
</li>
<li class="">
<strong>Production Environment</strong>
<br>
</li>
</ul><p>You currently have 1 feature flag in your ConfigCat setup. This appears to be a default feature flag that was automatically created when you set up your ConfigCat account. You can use this to test the feature flag functionality, or create additional feature flags as needed for your application.</p><p></p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>You’ll need to click <code>Run tool</code> or <code>Allow once</code> each time the AI agent tries to interact with the ConfigCat API. MCP servers require user approval before calling external APIs as a security measure. You can review the actual API request payload here before you accept it.</p></div></div>
<p>If you check your <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a> you will see your first feature flag automatically created by the ConfigCat registration:</p>
<img alt="My First Feature Flag" src="https://configcat.com/blog/assets/mcp-server-feature-flags/feature-flag_192dpi.png" width="1084" height="259" decoding="async" loading="lazy" class="zoomable">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-a-feature-flag">Creating a Feature Flag<a href="https://configcat.com/blog/mcp-server-feature-flags/#creating-a-feature-flag" class="hash-link" aria-label="Direct link to Creating a Feature Flag" title="Direct link to Creating a Feature Flag" translate="no">​</a></h3>
<p>Let's ask the AI agent to create a new feature flag:</p>
<div class="qa-row qa-row--human"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Prompt:</p><p class="qa-row__text"></p><p>Create a feature flag called "My New Awesome Feature"</p><p></p></div></div>
<div class="qa-row qa-row--ai"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Answer:</p><p class="qa-row__text"></p><p>I'll create a new feature flag called "My New Awesome Feature" for you. Let me add it to your "Main Config".<br></p><br><p>✅ <strong>Feature Flag Created Successfully</strong><br>
<strong>Name:</strong> My New Awesome Feature<br>
<strong>Key:</strong> <code>myNewAwesomeFeature</code><br>
<strong>Type:</strong> Boolean<br>
<strong>Description:</strong> A new awesome feature flag for testing<br></p><br><strong>Initial Values:</strong><br><ul>
<li class=""><strong>Test Environment:</strong> <code>false</code> (disabled)</li>
<li class=""><strong>Production Environment:</strong> <code>false</code> (disabled)</li>
</ul><p>The feature flag has been added to your "Main Config" and is currently disabled in both environments.</p><p></p></div></div>
<p>If you check your <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a> you will see the newly created feature flag:</p>
<img alt="My New Awesome Feature Flag is OFF" src="https://configcat.com/blog/assets/mcp-server-feature-flags/feature-flag-off_192dpi.png" width="1084" height="216" decoding="async" loading="lazy" class="zoomable">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="updating-a-feature-flag">Updating a Feature Flag<a href="https://configcat.com/blog/mcp-server-feature-flags/#updating-a-feature-flag" class="hash-link" aria-label="Direct link to Updating a Feature Flag" title="Direct link to Updating a Feature Flag" translate="no">​</a></h3>
<div class="qa-row qa-row--human"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Prompt:</p><p class="qa-row__text"></p><p>Turn the new awesome feature flag ON</p><p></p></div></div>
<div class="qa-row qa-row--ai"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Answer:</p><p class="qa-row__text"></p><p>I'll turn on your new awesome feature flag in both environments. Let me update the values to <code>true</code> for both Test and Production environments.<br></p><br><p>✅ <strong>Feature Flag Turned ON Successfully!</strong><br>
Your "My New Awesome Feature" feature flag is now <strong>enabled</strong> in both environments:<br>
<strong>Current Status:</strong><br></p><ul>
<li class=""><strong>Test Environment:</strong> ✅ <strong>ON</strong> (<code>true</code>)</li>
<li class=""><strong>Production Environment:</strong> ✅ <strong>ON</strong> (<code>true</code>)</li>
</ul><strong>Feature Flag Details:</strong><ul>
<li class=""><strong>Name:</strong> My New Awesome Feature</li>
<li class=""><strong>Key:</strong> <code>myNewAwesomeFeature</code></li>
<li class=""><strong>Type:</strong> Boolean</li>
<li class=""><strong>Default Value:</strong> <code>true</code> (enabled for all users)</li>
</ul><p>The feature flag is now live and will return true for all users in both your Test and Production environments. You can use the key <code>myNewAwesomeFeature</code> in your application code to check if this feature is enabled.</p><p></p></div></div>
<p>Checking the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">dashboard</a> you can see that the feature flag is turned on:</p>
<img alt="My New Awesome Feature Flag is ON" src="https://configcat.com/blog/assets/mcp-server-feature-flags/feature-flag-on_192dpi.png" width="1084" height="216" decoding="async" loading="lazy" class="zoomable">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="user-targeting">User Targeting<a href="https://configcat.com/blog/mcp-server-feature-flags/#user-targeting" class="hash-link" aria-label="Direct link to User Targeting" title="Direct link to User Targeting" translate="no">​</a></h3>
<p>Let's ask the AI agent to do something a little bit more complicated:</p>
<div class="qa-row qa-row--human"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Prompt:</p><p class="qa-row__text"></p><p>turn the "myNewAwesomeFeature" ON for company.com employees</p><p></p></div></div>
<div class="qa-row qa-row--ai"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Answer:</p><p class="qa-row__text"></p><p>I'll set up targeting rules to turn on the "myNewAwesomeFeature" feature flag only for employees of company.com. I'll create a targeting rule that checks if the user's email ends with "@company.com".<br></p><br><p>✅ <strong>Feature Flag Configured for company.com Employees Only!</strong><br>
Perfect! I've successfully configured your "My New Awesome Feature" feature flag to be enabled only for employees of company.com. Here's how it now works:<br></p><br><p><strong>Feature Flag:</strong> <code>myNewAwesomeFeature</code><br>
<strong>Default Value:</strong> <code>false</code> (disabled for everyone by default)<br></p><br><strong>Targeting Rule:</strong><br><ul>
<li class=""><strong>Condition:</strong> User's email ends with <code>@company.com</code></li>
<li class=""><strong>Result:</strong> <code>true</code> (feature enabled)</li>
<li class=""><strong>Applied to:</strong> Both Test and Production environments</li>
</ul><strong>How It Works:</strong><br><ol>
<li class=""><strong>company.com Employees</strong> (emails ending with <code>@company.com</code>): ✅ Feature ON<br></li>
<li class=""><strong>All Other Users:</strong> ❌ Feature OFF</li>
</ol><strong>Example Usage in Your Code:</strong><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// When evaluating the feature flag</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> user </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user123"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">email</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"john.doe@company.com"</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// company.com employee</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> isFeatureEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"myNewAwesomeFeature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Returns: true (for company.com employees)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> regularUser </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">identifier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user456"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">email</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user@example.com"</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Regular user</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> isFeatureEnabledForRegular </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"myNewAwesomeFeature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> regularUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Returns: false (for other employees)</span><br></div></code></pre></div></div><p>The feature flag is now live and will automatically enable the feature only for users with company.com email addresses while keeping it disabled for everyone else!</p><p></p></div></div>
<p>By checking the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a>, you can see that the AI figured out it can enable the feature for company.com employees by inspecting email addresses: if an address ends with <code>@company.com</code>, it enables the feature; otherwise, it doesn’t.</p>
<img alt="My New Awesome Feature Flag with targeting rule" src="https://configcat.com/blog/assets/mcp-server-feature-flags/feature-flag-targeting-rule_192dpi.png" width="1084" height="407" decoding="async" loading="lazy" class="zoomable">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="evaluating-a-feature-flag-with-ai-agents">Evaluating a Feature Flag with AI Agents<a href="https://configcat.com/blog/mcp-server-feature-flags/#evaluating-a-feature-flag-with-ai-agents" class="hash-link" aria-label="Direct link to Evaluating a Feature Flag with AI Agents" title="Direct link to Evaluating a Feature Flag with AI Agents" translate="no">​</a></h3>
<p>You can also use the AI agent for feature flag evaluation:</p>
<div class="qa-row qa-row--human"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Prompt:</p><p class="qa-row__text"></p><p>Evaluate the "myNewAwesomeFeature" flag for the user with email: <span>peter</span>@<span>company.com</span></p><p></p></div></div>
<div class="qa-row qa-row--ai"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Answer:</p><p class="qa-row__text"></p><p>Based on the targeting rule configured, let me evaluate the "myNewAwesomeFeature" flag for the user with email <code>peter@company.com</code>:</p><br><p><strong>Evaluation Result: ✅ TRUE (ON)</strong></p><p><strong>Reasoning:</strong></p><ul>
<li class=""><strong>Targeting Rule:</strong> IF Email ends with <code>@company.com</code> THEN return <code>true</code></li>
<li class=""><strong>User Email:</strong> <code>peter@company.com</code></li>
<li class=""><strong>Match:</strong> ✅ Yes, the email ends with <code>@company.com</code></li>
<li class=""><strong>Result:</strong> The flag returns <code>true</code> (feature is ON)</li>
</ul><p>Since Peter's email address (<code>peter@company.com</code>) ends with <code>@company.com</code>, he matches the targeting rule for company.com employees, so the feature flag will be enabled for him in both Test and Production environments.</p><p></p></div></div>
<p>Let's evaluate the feature flag for a user with email: <code>john@example.com</code></p>
<div class="qa-row qa-row--human"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Prompt:</p><p class="qa-row__text"></p><p>Evaluate the "myNewAwesomeFeature" flag for the user with email: <span>john</span>@<span>example.com</span></p><p></p></div></div>
<div class="qa-row qa-row--ai"><div class="qa-row__icon"></div><div class="qa-row__content"><p class="qa-row__label">Answer:</p><p class="qa-row__text"></p><p>Based on the targeting rule configured, let me evaluate the "myNewAwesomeFeature" flag for the user with email <code>john@example.com</code>:</p><br><p><strong>Evaluation Result: ❌ FALSE (OFF)</strong></p><p><strong>Reasoning:</strong></p><ul>
<li class=""><strong>Targeting Rule:</strong> IF Email ends with <code>@company.com</code> THEN return <code>true</code></li>
<li class=""><strong>User Email:</strong> <code>john@example.com</code></li>
<li class=""><strong>Match:</strong> ❌ No, the email ends with <code>@example.com</code>, not <code>@company.com</code></li>
<li class=""><strong>Default Value:</strong> <code>false</code> (OFF)</li>
<li class=""><strong>Result:</strong> The flag returns <code>false</code> (feature is OFF)</li>
</ul><p>Since John's email address (<code>john@example.com</code>) does NOT end with <code>@company.com</code>, he does not match the targeting rule for company.com employees. Therefore, he gets the default value of <code>false</code>, meaning the feature flag will be disabled for him in both Test and Production environments.</p><p></p></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-note" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="m13 20 7-7M13 20v-6a1 1 0 0 1 1-1h6V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Note that there’s no feature-flag evaluation endpoint in the ConfigCat Public Management API. To evaluate flags, you’d need to use one of <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">the ConfigCat SDKs</a>. When you evaluate a feature flag via the ConfigCat MCP server, the AI model is running the evaluation logic.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="additional-feature-flag-mcp-prompt-examples">Additional Feature Flag MCP Prompt Examples<a href="https://configcat.com/blog/mcp-server-feature-flags/#additional-feature-flag-mcp-prompt-examples" class="hash-link" aria-label="Direct link to Additional Feature Flag MCP Prompt Examples" title="Direct link to Additional Feature Flag MCP Prompt Examples" translate="no">​</a></h3>
<ul>
<li class="">
<p>Cloning a feature flag:</p>
<blockquote>
<p>Create a new feature flag by cloning the configuration of the "myNewAwesomeFeature" flag, and name it "myAnotherAwesomeFeature".</p>
</blockquote>
</li>
<li class="">
<p>Updating a feature flag description</p>
<blockquote>
<p>Update the "myNewAwesomeFeature" flag description: "When enabled, show my awesome new feature.”</p>
</blockquote>
</li>
<li class="">
<p>Listing <a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">Zombie (Stale)</a> feature flags older than 6 days</p>
<blockquote>
<p>List the stale feature flags that haven’t been modified in the past 6 days.</p>
</blockquote>
</li>
<li class="">
<p>Sending <a href="https://configcat.com/docs/advanced/team-management/team-management-basics/" target="_blank" rel="noopener noreferrer" class="">Invitation</a></p>
<blockquote>
<p>Invite <span>sarah</span>@<span>example.com</span> to the "Main" product with "Administrators" permissions.</p>
</blockquote>
</li>
<li class="">
<p>Reviewing Audit log activities</p>
<blockquote>
<p>Show who last modified the "myNewAwesomeFeature" flag, and to what.</p>
</blockquote>
</li>
<li class="">
<p>Creating <a href="https://configcat.com/docs/targeting/targeting-rule/segment-condition/" target="_blank" rel="noopener noreferrer" class="">User Segment</a></p>
<blockquote>
<p>Create a “beta users” segment with these email addresses: <span>sarah</span>@<span>example.com</span>, <span>john</span>@<span>example.com</span>.
Enable the "myNewAwesomeFeature" flag for the "beta users" segment.</p>
</blockquote>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/mcp-server-feature-flags/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h3>
<p>In this article, you learned how to use ConfigCat feature flags with AI agents. This can make feature flagging easier, and the AI agent can even handle quite complex tasks using natural language.
Always double-check what the AI system is doing before you accept its changes.</p>
<p>The MCP server can help not only with managing ConfigCat feature flags, but also with coding. A future blog post may cover that in more detail. In the meantime, here are a few docs if you want to dig deeper into the ConfigCat model context protocol:</p>
<ul>
<li class=""><a href="https://configcat.com/docs/advanced/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server documentation</a></li>
<li class=""><a href="https://github.com/configcat/mcp-server" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server GitHub repository</a></li>
<li class=""><a href="https://github.com/configcat/mcp-server?tab=readme-ov-file#available-tools" target="_blank" rel="noopener noreferrer" class="">ConfigCat MCP server available tools</a></li>
<li class=""><a href="https://configcat.com/docs/api/reference/configcat-public-management-api/" target="_blank" rel="noopener noreferrer" class="">Management API Reference</a></li>
</ul>
<p>For more on feature flags, check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<style>.qa-row{color:var(--ifm-font-color-base);border:1px solid var(--ifm-color-emphasis-200);border-radius:var(--ifm-global-radius);align-items:flex-start;gap:12px;margin:1.5rem 0;padding:1.25rem 1.5rem;transition:background .2s,border-color .2s;display:flex}.qa-row__icon{background-color:var(--ifm-color-emphasis-100);width:28px;height:28px;box-shadow:inset 0 0 0 1px var(--ifm-color-emphasis-300);background-position:50%;background-repeat:no-repeat;background-size:18px 18px;border-radius:999px;flex:0 0 28px;position:relative}.qa-row__content{min-width:0}.qa-row__label{margin:0 0 2px;font-size:.98rem;font-weight:600}.qa-row__text{color:var(--ifm-color-emphasis-700);margin:0;line-height:1.6}.qa-row__text p{margin:0}.qa-row--human .qa-row__icon:before{content:"";mask:url(/blog/assets/mcp-server-feature-flags/person.svg) 50%/18px 18px no-repeat;background-color:var(--ifm-color-emphasis-600);width:18px;height:18px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-webkit-mask:url(/blog/assets/mcp-server-feature-flags/person.svg) 50%/18px 18px no-repeat}.qa-row--ai .qa-row__icon:before{content:"";mask:url(/blog/assets/mcp-server-feature-flags/robot.svg) 50%/18px 18px no-repeat;background-color:var(--ifm-color-emphasis-600);width:18px;height:18px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-webkit-mask:url(/blog/assets/mcp-server-feature-flags/robot.svg) 50%/18px 18px no-repeat}html[data-theme=dark] .qa-row__icon{background-color:var(--ifm-color-emphasis-200);box-shadow:inset 0 0 0 1px var(--ifm-color-emphasis-400)}html[data-theme=dark] .qa-row--human .qa-row__icon:before,html[data-theme=dark] .qa-row--ai .qa-row__icon:before{background-color:#fff}</style>]]></content:encoded>
            <category>AI</category>
            <category>MCP server</category>
            <category>ConfigCat</category>
            <category>feature flags</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags in the Age of AI: Complexity, Data, and Finding the Right Balance]]></title>
            <link>https://configcat.com/blog/feature-flags-in-the-age-of-ai/</link>
            <guid>https://configcat.com/blog/feature-flags-in-the-age-of-ai/</guid>
            <pubDate>Fri, 26 Sep 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Statsig + OpenAI news shows how feature flags drive modern software. Learn to ship faster, stay in control, and avoid vendor lock-in.]]></description>
            <content:encoded><![CDATA[<p>The feature flagging and experimentation space is heating up fast. <a href="https://www.cnbc.com/2025/09/02/openai-buys-statsig-for-1point1-billion-hires-ceo-as-applications-exec.html" target="_blank" rel="noopener noreferrer" class="">OpenAI’s acquisition of Statsig</a> shows just how important feature flag management has become and signals that the industry is moving toward AI-assisted, data-driven systems that optimize every release automatically.</p>
<p>This isn’t just another headline in the AI news cycle. It’s a sign of where software delivery is heading: toward AI-assisted, data-heavy development workflows where every release is measured, analyzed, and optimized.</p>
<p>For some teams, that’s the dream. For others, it’s just another layer of complexity standing between them and shipping code.</p>
<img alt="Feature flags vs environment variables cover" src="https://configcat.com/blog/assets/ff-in-the-age-of-ai/feature-flags-in-age-of-ai-configcat-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="experimentation-is-growing-up">Experimentation Is Growing Up<a href="https://configcat.com/blog/feature-flags-in-the-age-of-ai/#experimentation-is-growing-up" class="hash-link" aria-label="Direct link to Experimentation Is Growing Up" title="Direct link to Experimentation Is Growing Up" translate="no">​</a></h2>
<p>If you’ve been following the feature management space, you’ve probably noticed how quickly it’s evolving. New tools, new metrics, and new integrations are appearing all the time,  promising to catch every issue, measure every release, and optimize every deployment.</p>
<p>For teams running dozens of experiments a week, this is exciting. It means faster learning, more control, and fewer late-night firefights when something goes wrong.</p>
<p>But for many teams, all of this can start to feel like too much. Instead of making shipping easier, it can feel like you’ve added another layer of process and tooling just to get code into production.
You might just want to <a href="https://configcat.com/docs/targeting/percentage-options/" target="_blank" rel="noopener noreferrer" class="">roll out a feature gradually</a>, <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/#ab-testing-and-feature-flags" target="_blank" rel="noopener noreferrer" class="">run a simple A/B test</a>, and move on  without spinning up a data pipeline or wiring up a dozen dashboards.</p>
<p>And you might also be wondering:</p>
<ul>
<li class=""><em>Do we really need AI to ship a simple feature?</em></li>
<li class=""><em>Who owns all the data we generate from these experiments?</em></li>
<li class=""><em>Are we comfortable sharing that data with yet another platform?</em></li>
<li class=""><em>Are we locking ourselves into a vendor we can’t easily leave later?</em></li>
</ul>
<p>These are smart, thoughtful questions. Feature flags are supposed to reduce stress, not add it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-philosophy-of-simplicity">A Philosophy of Simplicity<a href="https://configcat.com/blog/feature-flags-in-the-age-of-ai/#a-philosophy-of-simplicity" class="hash-link" aria-label="Direct link to A Philosophy of Simplicity" title="Direct link to A Philosophy of Simplicity" translate="no">​</a></h2>
<p>Feature flags can be powerful without being complicated. For many teams, the right approach is one that keeps them in control while staying lightweight and easy to use.</p>
<p>That means:</p>
<ul>
<li class=""><strong>Simplicity:</strong> Roll out gradually, <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer" class="">target users</a>, and <a href="https://configcat.com/blog/2022/05/09/feature-flag-rollbacks-for-product-managers/" target="_blank" rel="noopener noreferrer" class="">roll back instantly</a>, without weeks of setup.</li>
<li class=""><strong>No Vendor Lock-In:</strong> Your flags and configs should be portable so you can switch providers if you need to.</li>
<li class=""><strong>Zero Data Collection:</strong> Your end-user data stays with you, not your feature flag vendor.</li>
<li class=""><strong>Transparent Pricing:</strong> No hidden surprises, no confusing billing models,  just clear, predictable costs.</li>
<li class=""><strong>Bring Your Own Stack:</strong> Integrate with the analytics and monitoring tools you already use and love, <a href="https://configcat.com/docs/integrations/google-analytics/" target="_blank" rel="noopener noreferrer" class="">Google Analytics</a>, <a href="https://configcat.com/docs/integrations/mixpanel/" target="_blank" rel="noopener noreferrer" class="">Mixpanel</a>, <a href="https://configcat.com/docs/integrations/datadog/" target="_blank" rel="noopener noreferrer" class="">Datadog,</a> whatever fits your workflow. No need to rip and replace your existing stack just to adopt feature flags.</li>
</ul>
<p>These principles keep teams in control of their release process, their data, and their budget, so they can focus on building great products.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="choosing-the-right-level-of-control">Choosing the Right Level of Control<a href="https://configcat.com/blog/feature-flags-in-the-age-of-ai/#choosing-the-right-level-of-control" class="hash-link" aria-label="Direct link to Choosing the Right Level of Control" title="Direct link to Choosing the Right Level of Control" translate="no">​</a></h2>
<p>The Statsig + OpenAI news shows that feature flags and experimentation are no longer “nice-to-have”:  they’re part of the infrastructure for modern software teams.</p>
<p>But there’s no one-size-fits-all solution.</p>
<p>Some organizations thrive on advanced experimentation pipelines, AI-assisted rollouts, and deep observability. Others simply need a privacy-first, easy-to-implement feature flagging tool that gets out of the way and lets them ship with confidence.
The best solution is the one that helps your team:</p>
<ul>
<li class="">Ship faster, with less stress</li>
<li class="">Stay flexible as your needs evolve</li>
<li class="">Keep full ownership of your data</li>
<li class="">Work with the tools you already love</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="final-thoughts">Final Thoughts<a href="https://configcat.com/blog/feature-flags-in-the-age-of-ai/#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Feature flagging should feel like a superpower, not a burden.</p>
<p>As the ecosystem grows more complex, it’s worth asking:</p>
<ul>
<li class=""><em>Are we keeping our release process as simple as it needs to be?</em></li>
<li class="">Are we still in control of our own data?</li>
<li class=""><em>Could we switch providers tomorrow if we wanted to?</em></li>
</ul>
<p>Answering these questions can help teams find the right balance between innovation and control, and keep shipping fast, safe, and user-focused.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-reflect-on-your-setup">Ready to Reflect on Your Setup?<a href="https://configcat.com/blog/feature-flags-in-the-age-of-ai/#ready-to-reflect-on-your-setup" class="hash-link" aria-label="Direct link to Ready to Reflect on Your Setup?" title="Direct link to Ready to Reflect on Your Setup?" translate="no">​</a></h2>
<p>Take a moment to look at how your team is handling rollouts today. Could things be simpler, safer, or more privacy-friendly?
If the answer is yes, it might be time to explore tools that help you:</p>
<ul>
<li class="">Keep your data yours</li>
<li class="">Roll out safely</li>
<li class="">Stay flexible, no vendor lock-in required</li>
</ul>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">Explore ConfigCat</a> and see how you can bring simplicity, transparency, and control back to your release process.</p>
<p>You can also check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>experimentation</category>
            <category>software release best practices</category>
            <category>AI in software delivery</category>
            <category>Statsig</category>
        </item>
        <item>
            <title><![CDATA[How to Dynamically Update User Segments in ConfigCat]]></title>
            <link>https://configcat.com/blog/update-user-segments-in-configcat/</link>
            <guid>https://configcat.com/blog/update-user-segments-in-configcat/</guid>
            <pubDate>Fri, 29 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to automatically add or remove users from ConfigCat feature flag segments using ConfigCat’s Update Segment API]]></description>
            <content:encoded><![CDATA[<p>In modern software development, feature flags are a must-have. They let teams release features gradually, run A/B tests, and control access for different user groups. But there's a common challenge: How do you keep a list of dynamic user segments (like beta testers) always up to date without manually editing the dashboard every time?</p>
<p>To tackle this challenge, I'll show you how to update user segments in ConfigCat dynamically, including examples of setting up and using the <a href="https://api.configcat.com/docs/#tag/Segments/operation/update-segment" target="_blank" rel="noopener noreferrer" class="">ConfigCat's Update Segment API</a>, best practices for managing segment details, and tips for integrating this functionality into your development workflow.</p>
<img alt="How to Update User Segments Using the Segments API cover" src="https://configcat.com/blog/assets/update-user-segments-with-configcat-segment-api/update-user-segments-with-configcat-segment-api-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-challenge-dynamic-beta-user-management">The Challenge: Dynamic Beta User Management<a href="https://configcat.com/blog/update-user-segments-in-configcat/#the-challenge-dynamic-beta-user-management" class="hash-link" aria-label="Direct link to The Challenge: Dynamic Beta User Management" title="Direct link to The Challenge: Dynamic Beta User Management" translate="no">​</a></h2>
<p>Let’s consider the following scenario described by a customer:</p>
<blockquote>
<p>"For a gradual rollout, we would like to have something like 'beta users,' which is a list of user IDs that I can add to the segment and use in our flags. The issue is that this list is dynamic and can change as we add new users and remove older ones. Do you have any creative way to interact with segments dynamically"?</p>
</blockquote>
<p>Manually updating this list through the <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat dashboard</a> could give room for errors, be hard to manage, and also be time-consuming.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-solution-using-the-configcat-update-segment-api">The Solution: Using the ConfigCat Update Segment API<a href="https://configcat.com/blog/update-user-segments-in-configcat/#the-solution-using-the-configcat-update-segment-api" class="hash-link" aria-label="Direct link to The Solution: Using the ConfigCat Update Segment API" title="Direct link to The Solution: Using the ConfigCat Update Segment API" translate="no">​</a></h2>
<p><a href="https://api.configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat's API</a> provides a powerful way to update segments programmatically, making it efficient and ideal for managing dynamic user lists. Integrating the <a href="https://api.configcat.com/docs/#tag/Segments/operation/update-segment" target="_blank" rel="noopener noreferrer" class="">update segment API</a> into your user management workflow ensures your feature flag targeting remains accurate.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="understanding-segments-in-configcat">Understanding Segments in ConfigCat<a href="https://configcat.com/blog/update-user-segments-in-configcat/#understanding-segments-in-configcat" class="hash-link" aria-label="Direct link to Understanding Segments in ConfigCat" title="Direct link to Understanding Segments in ConfigCat" translate="no">​</a></h2>
<p>Segments are used to group users based on any of their properties (userId, email, role, account plan, etc.). They make it easy to control who gets access to specific features by letting you add or remove users at any time.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-the-update-segment-api-works">How the Update Segment API Works<a href="https://configcat.com/blog/update-user-segments-in-configcat/#how-the-update-segment-api-works" class="hash-link" aria-label="Direct link to How the Update Segment API Works" title="Direct link to How the Update Segment API Works" translate="no">​</a></h3>
<p>The <a href="https://api.configcat.com/docs/#tag/Segments/operation/update-segment" target="_blank" rel="noopener noreferrer" class="">Update Segment API</a> allows you to modify the comparison values used in your segments to determine which users belong to a segment. The API endpoint to update a user segment is:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token constant" style="color:rgb(130, 170, 255)">PUT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">v1</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">segments</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">segmentId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="path-parameters">Path Parameters<a href="https://configcat.com/blog/update-user-segments-in-configcat/#path-parameters" class="hash-link" aria-label="Direct link to Path Parameters" title="Direct link to Path Parameters" translate="no">​</a></h4>
<ul>
<li class="">segmentId (UUID, required): This is the identifier of the segment that needs to be updated.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="request-body-schema">Request Body Schema<a href="https://configcat.com/blog/update-user-segments-in-configcat/#request-body-schema" class="hash-link" aria-label="Direct link to Request Body Schema" title="Direct link to Request Body Schema" translate="no">​</a></h4>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Beta Users"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"description"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Active participants in our beta testing program"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"comparisonAttribute"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"email"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"comparator"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"isOneOf"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"comparisonValue"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user1@example.com,user2@example.com,user3@example.com"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-fields-explained">Key Fields Explained<a href="https://configcat.com/blog/update-user-segments-in-configcat/#key-fields-explained" class="hash-link" aria-label="Direct link to Key Fields Explained" title="Direct link to Key Fields Explained" translate="no">​</a></h4>
<ul>
<li class=""><strong>name</strong>: A descriptive name for your segment (Can be no longer than 255 characters).</li>
<li class=""><strong>description</strong>: Additional information about the purpose of the segment (Can be no longer than 1000 characters).</li>
<li class=""><strong>comparisonAttribute</strong>: This is the user attribute to use for evaluation (e.g. email, userId, role, etc.).</li>
<li class=""><strong>comparator</strong>: The evaluation operator (in this case, "isOneOf" checks if the user attribute matches any value in a comma-separated list).</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle" style="fill:none" viewBox="0 0 24 24"><path stroke="none" d="M0 0h24v24H0z"></path><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>The choice of comparator is dependent on the logic behind your segment update usage. Other values that can be used are: <strong>isNotOneOf</strong>, <strong>contains</strong>, <strong>doesNotContain</strong>, etc. Visit the <a href="https://api.configcat.com/docs/#tag/Segments/operation/update-segment" target="_blank" rel="noopener noreferrer" class="">update segment section</a> in the docs to view the valid comparators.</p></div></div>
<ul>
<li class=""><strong>comparisonValue</strong> (string): The actual values to compare against (a comma-separated list of user identifiers).</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="implementing-a-dynamic-beta-user-management-system">Implementing a Dynamic Beta User Management System<a href="https://configcat.com/blog/update-user-segments-in-configcat/#implementing-a-dynamic-beta-user-management-system" class="hash-link" aria-label="Direct link to Implementing a Dynamic Beta User Management System" title="Direct link to Implementing a Dynamic Beta User Management System" translate="no">​</a></h2>
<p>Here's a step-by-step guide to implementing an automated solution for managing a dynamic list of beta users:</p>
<ol>
<li class=""><strong>Create the Initial Segment</strong></li>
</ol>
<p>First, create a new segment through the ConfigCat dashboard or API. Note the segmentId as you'll need it for future updates.</p>
<ol start="2">
<li class=""><strong>Develop an Update Script</strong></li>
</ol>
<p>Create a script that will:</p>
<ul>
<li class="">Retrieve the current list of beta users from your user database or system</li>
<li class="">Format them into a comma-separated string</li>
<li class="">Call the Update Segment API to modify the segment</li>
</ul>
<ol start="3">
<li class=""><strong>Sample Implementation (JavaScript)</strong></li>
</ol>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ConfigCat API Configuration</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">API_BASE_URL</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"https://api.configcat.com/v1"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">API_KEY</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_API_KEY"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Your ConfigCat Management API key</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SEGMENT_ID</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR_SEGMENT_ID"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// The UUID of your beta users segment</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">/**</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic"> * Retrieve current beta users from your database.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic"> * This is just a placeholder - implement your specific data retrieval logic.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">*/</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getCurrentBetaUsers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Replace with your actual database query</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// This could be an API call, database query, etc.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"user1@example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"user2@example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"new_beta_user@example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">/**</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic"> * Update the beta users segment in ConfigCat with the current list.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">*/</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">updateBetaUsersSegment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">userList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> headers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"Authorization"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">bearer </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">API_KEY</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"Content-Type"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"application/json"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Format the user list as a comma-separated string</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> comparisonValue </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> userList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">join</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">","</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> payload </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Beta Users"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"description"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Automatically updated list of current beta testers"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"comparisonAttribute"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"email"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Or userId, depending on your setup</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"comparator"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"isOneOf"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string-property property">"comparisonValue"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> comparisonValue</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">API_BASE_URL</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">/segments/</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">SEGMENT_ID</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">method</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'PUT'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">headers</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> headers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token literal-property property">body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">ok</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Successfully updated beta users segment with </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">userList</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">length</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)"> users</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Return the response data if needed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Failed to update segment: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">status</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword control-flow" style="font-style:italic">throw</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">API request failed with status </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">status</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Error updating segment:"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword control-flow" style="font-style:italic">throw</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">/**</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic"> * Main execution function</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">*/</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> currentBetaUsers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getCurrentBetaUsers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">updateBetaUsersSegment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">currentBetaUsers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Failed to update beta users segment:"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Execute the update</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="best-practices-and-considerations">Best Practices and Considerations<a href="https://configcat.com/blog/update-user-segments-in-configcat/#best-practices-and-considerations" class="hash-link" aria-label="Direct link to Best Practices and Considerations" title="Direct link to Best Practices and Considerations" translate="no">​</a></h2>
<ol>
<li class="">
<p><strong>API Rate Limiting</strong>: Be mindful of <a href="https://configcat.com/docs/api/reference/configcat-public-management-api/#throttling-and-rate-limits" target="_blank" rel="noopener noreferrer" class="">ConfigCat's API rate limits</a>. For most use cases, it is ideal and advisable to use the API endpoint once or twice per day or when significant changes occur.</p>
</li>
<li class="">
<p><strong>Segment Size Limitations</strong>: The comparison value has a character limit, so if your beta user list grows very large, consider these approaches:
Having users split across multiple segments
Use a different targeting approach, such as introducing a new property: "<strong>isBetaUser</strong>" attribute in user objects.</p>
</li>
<li class="">
<p><strong>Error Handling</strong>: Implement proper error handling and notifications in your update script to ensure you're alerted if the segment fails to update.</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://configcat.com/blog/update-user-segments-in-configcat/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>The <a href="https://api.configcat.com/docs/#tag/Segments/operation/update-segment" target="_blank" rel="noopener noreferrer" class="">ConfigCat Update Segment API</a> is a great tool for dynamically updating your user segments in ConfigCat. By automating segment updates, you can ensure your beta users always have access to the features they should be testing, without the burden of managing the list manually.</p>
<p>This approach highlights ConfigCat's flexibility and shows how the API can integrate with your workflows to build a more efficient, scalable feature management system. ConfigCat also provides SDKs for major <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer" class="">programming languages and frameworks</a> for easy integrations.</p>
<p>For more on feature flags, check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>how to</category>
            <category>feature flags</category>
            <category>phased rollout</category>
            <category>testing</category>
            <category>user segment</category>
            <category>API</category>
        </item>
        <item>
            <title><![CDATA[Beyond Environment Variables: When to Use Feature Flags (and Why)]]></title>
            <link>https://configcat.com/blog/feature-flags-vs-environment-variables/</link>
            <guid>https://configcat.com/blog/feature-flags-vs-environment-variables/</guid>
            <pubDate>Fri, 25 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Uncover the key differences between feature flags and environment variables in the context of feature delivery and remote configuration.]]></description>
            <content:encoded><![CDATA[<p>When talking to devs in the software development community about feature flags, a question that often comes up is, “Can’t I just use environment variables for that?” It's a fair question; both can influence how an app behaves. But under the hood, they serve very different purposes. Let's break it down.</p>
<img alt="Feature flags vs environment variables cover" src="https://configcat.com/blog/assets/feature-flags-vs-envars/feature-flags-vs-environment-variables-cover_96dpi.png" width="1200" height="630" decoding="async" loading="lazy">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-an-environment-variable">What's an Environment Variable?<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#whats-an-environment-variable" class="hash-link" aria-label="Direct link to What's an Environment Variable?" title="Direct link to What's an Environment Variable?" translate="no">​</a></h2>
<p>Environment variables are key-value pairs used to supply configuration values to your application. They typically live in your app’s runtime environment. You can set environment variables through the command line, CI/CD pipelines, or hosting platform settings using a config file.</p>
<p>Environment variables are commonly used in the following scenarios:</p>
<ul>
<li class="">Applying environment-specific data such as port numbers and database URLs.</li>
<li class="">Keeping sensitive data such as API keys and credentials out of your source code.</li>
<li class="">Changing software behavior based on environment (e.g., setting API rate limits in a production environment).</li>
</ul>
<p>Simple, dependable, and great for bootstrapping config. But they have limits.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-a-feature-flag">What's a Feature Flag?<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#whats-a-feature-flag" class="hash-link" aria-label="Direct link to What's a Feature Flag?" title="Direct link to What's a Feature Flag?" translate="no">​</a></h2>
<p>A <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer" class="">feature flag</a> or feature toggle represents a boolean-type setting value that allows development teams and product managers to toggle features on or off. Feature flags allow you to separate deployments from feature releases. They are typically used in if-else statements to make features visible to an entire user base or, with precise <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">targeting</a>, to specific audiences and individual users.</p>
<p>Common feature flags use cases include:</p>
<ul>
<li class="">Progressive delivery (e.g., <a href="https://configcat.com/blog/2024/01/16/using-configcat-for-staged-rollouts-and-canary-releases/#what-are-staged-rollouts-and-canary-releases" target="_blank" rel="noopener noreferrer" class="">canary releases and staged rollouts</a>)</li>
<li class="">Trunk-based development</li>
<li class="">Experimentation and marketing campaigns (e.g., <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer" class="">A/B testing</a>)</li>
<li class=""><a href="https://configcat.com/docs/glossary/#kill-switch" target="_blank" rel="noopener noreferrer" class="">Kill switches</a> for cases where features are not working correctly</li>
</ul>
<p>They are typically managed using a feature management platform like <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer" class="">ConfigCat</a> or LaunchDarkly, or via a homegrown solution if you have the time and resources.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="understanding-the-differences">Understanding the Differences<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#understanding-the-differences" class="hash-link" aria-label="Direct link to Understanding the Differences" title="Direct link to Understanding the Differences" translate="no">​</a></h2>
<p>While feature flags and environment variables can both affect how applications behave, their similarities end there. Here are the factors that set them apart:</p>
<ul>
<li class="">
<p><strong>Redeployment:</strong> This is probably the biggest difference. Changing the value of an environment variable requires you to redeploy the application code or rebuild your app to reflect the changes. In contrast, when you toggle a feature flag, your app reflects the changes almost immediately without redeployment.</p>
</li>
<li class="">
<p><strong>Targeting:</strong> Feature flags enable you to roll out features to specific subsets of users or user segments based on contextual data, such as country, email address, or device type. Environment variables, on the other hand, do not support <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer" class="">user targeting and segmentation</a>.</p>
</li>
<li class="">
<p><strong>Values:</strong> Environment variable values can only be strings. While you can pass numbers and booleans as strings, you need to parse them in your app before use. Complex values, such as objects, must be stringified first. Feature flags, on the other hand, are traditionally boolean values, but modern systems also support strings, numbers, and even JSON objects.</p>
</li>
</ul>
<p>Now that we’ve covered the differences, let’s look at the pros and cons of using feature flags and environment variables to modify application behavior.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="feature-flags-vs-environment-variables-quick-comparison">Feature Flags vs. Environment Variables: Quick Comparison<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#feature-flags-vs-environment-variables-quick-comparison" class="hash-link" aria-label="Direct link to Feature Flags vs. Environment Variables: Quick Comparison" title="Direct link to Feature Flags vs. Environment Variables: Quick Comparison" translate="no">​</a></h2>
<table><thead><tr><th>Feature</th><th>Environment Variables</th><th>Feature Flags</th></tr></thead><tbody><tr><td>Does change require code deployment?</td><td>✅<!-- --> Yes</td><td>❌<!-- --> No</td></tr><tr><td>Supports targeting?</td><td>❌<!-- --> No</td><td>✅<!-- --> Yes</td></tr><tr><td>Value types</td><td>Strings only (must parse others)</td><td>Booleans, strings, numbers, JSON</td></tr><tr><td>Per-user control</td><td>❌<!-- --> Not possible</td><td>✅<!-- --> Easy to segment users</td></tr><tr><td>Frontend-safe?</td><td>❌<!-- --> Risky (can expose secrets)</td><td>✅<!-- --> With proper flag setup</td></tr><tr><td>Best for</td><td>Static config, secrets, bootstrapping</td><td>Dynamic features, rollouts, A/B tests</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pros-and-cons">Pros and Cons<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#pros-and-cons" class="hash-link" aria-label="Direct link to Pros and Cons" title="Direct link to Pros and Cons" translate="no">​</a></h2>
<p>In short, there are numerous benefits and drawbacks to using each, and it is crucial to make an informed decision about when to utilize each to align with best practices.</p>
<p>The pros of using environment variables are that they require no external tools and are language-agnostic. But the downsides are:</p>
<ul>
<li class="">Require redeployments</li>
<li class="">No user segmentation</li>
<li class="">Harder to manage at scale</li>
<li class="">Only handle strings</li>
</ul>
<p>On the other hand, feature flags have some downsides, such as making testing more complex and adding technical debt to your codebase if stale flags are not removed. However, they offer more benefits, such as:</p>
<ul>
<li class="">No redeployments needed</li>
<li class="">Fine-grained control over rollouts</li>
<li class="">Safer feature experimentation</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-use-when">What to Use When?<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#what-to-use-when" class="hash-link" aria-label="Direct link to What to Use When?" title="Direct link to What to Use When?" translate="no">​</a></h2>
<p>Use environment variables when:</p>
<ul>
<li class="">You need config only at startup</li>
<li class="">You don't need to target users</li>
<li class="">You're storing secrets or low-level infrastructure config</li>
</ul>
<p>Use feature flags when:</p>
<ul>
<li class="">You want to enable/disable features instantly</li>
<li class="">You are rolling out features to a subset of users</li>
<li class="">You need flexibility and safety during releases</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bonus-tips">Bonus Tips<a href="https://configcat.com/blog/feature-flags-vs-environment-variables/#bonus-tips" class="hash-link" aria-label="Direct link to Bonus Tips" title="Direct link to Bonus Tips" translate="no">​</a></h2>
<p>If you choose to use environment variables, check out <a href="https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Bvendor%5D%5B0%5D=Environment%20Variable" target="_blank" rel="noopener noreferrer" class="">OpenFeature's environment variable providers</a>. They support booleans, numbers, strings, and objects, and provide a nice API for evaluating these values. If you opt to use OpenFeature to manage your ConfigCat feature flags, take a look at our <a href="https://configcat.com/blog/2024/10/31/configcat-openfeature/" target="_blank" rel="noopener noreferrer" class="">OpenFeature guide</a>.</p>
<p>And if you choose feature flags, you should:</p>
<ul>
<li class="">Have the culture and tooling in place to remove <a href="https://configcat.com/docs/zombie-flags/" target="_blank" rel="noopener noreferrer" class="">stale (zombie) flags</a>.</li>
<li class="">Give your feature flags <a href="https://configcat.com/blog/2023/05/19/feature-flag-naming-conventions/" target="_blank" rel="noopener noreferrer" class="">descriptive names</a>.</li>
<li class="">Make your feature flags observable.</li>
</ul>
<p>ConfigCat can help you with all of the above (except the team culture part 😅). ConfigCat provides <a href="https://configcat.com/docs/zombie-flags/#managing-zombie-flags-in-configcat" target="_blank" rel="noopener noreferrer" class="">zombie flag management</a>, <a href="https://configcat.com/docs/integrations/overview/" target="_blank" rel="noopener noreferrer" class="">integrations</a> for monitoring and analytics platforms, and many other features that allow you to use feature flags and <a href="https://configcat.com/docs/glossary/remote-configuration/" target="_blank" rel="noopener noreferrer" class="">remote configuration</a> with ease. <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer" class="">Get started</a> with the generous forever free plan, or <a href="https://configcat.com/demo" target="_blank" rel="noopener noreferrer" class="">contact the team for a demo</a>.</p>
<p>You can also check out ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer" class="">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer" class="">X</a>, <a href="https://www.linkedin.com/company/configcat" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>environment variables</category>
            <category>environment</category>
            <category>comparison</category>
            <category>deployment</category>
        </item>
    </channel>
</rss>