Scenario Recipes
Real-world scenarios showing how Feature Flags for Craft CMS solves problems you already have.
1. Safe-Launch a Homepage Redesign #
You’re rebuilding a client’s homepage. The new homepage changes things up considerably: new hero section, restructured CTAs, and different content blocks. The client wants to see it on the live site before you flip the switch to roll it out.
You need a way to show on the new homepage in production without anyone seeing it except you and the client. Once they approve, you want to make it live with a single toggle. No additional deployment.
The Flag
| Property | Value |
|---|---|
| Name | homepage-redesign |
| Type | release |
| Enabled | true |
| Rollout % | 0 |
| Rules | user = 42 (your client’s user ID) |
Walkthrough
1. Create the flag in the control panel at Feature Flags > New. Set the name to homepage-redesign, type to Release, and toggle it on. Add a targeting rule: type user, value 42 (your client’s Craft user ID).
2. Wrap the homepage template with a flag check:
{# templates/_pages/homepage.twig #}
{% if craft.featureFlags.isEnabled('homepage-redesign') %}
{# New redesigned homepage #}
{% include '_partials/hero-v2' %}
{% include '_partials/features-grid' %}
{% include '_partials/testimonials-carousel' %}
{% else %}
{# Current homepage - untouched #}
{% include '_partials/hero' %}
{% include '_partials/features-list' %}
{% include '_partials/testimonials' %}
{% endif %}
3. Send the client a link. When they log in to Craft and visit the homepage, they see the new design. Everyone else sees the existing page. No one panics.
4. Client approves. Remove the user rule in the control panel so the flag has no targeting rules. With no rules and the flag enabled, it returns true for everyone — the redesign is live.
5. Slow rollout. Maybe you decide that you’d like to roll out the homepage redesign to only 25% of visitors just in case there’s a bug or unknown performance issue with the new mega menu and 4K video hero. Add a rollout percentage to 25 and then monitor the site.
6. Increase the rollout. Everything is looking snappy and no errors, so you increase the rollout percentage to 50, then 75, then 100 or empty.
7. Clean up. Once you’re confident, remove the {% if %} wrapper from the template, remove the old homepage partials, and delete the flag. Deploy the code changes and the homepage rollout is complete!
Zero downtime, zero risk. The client reviewed the actual production page instead of a staging approximation, and you went live with a click. If anything had gone sideways you could have toggled the flag off in seconds.
2. Gradually Roll Out a New Checkout Flow #
It’s time to change your checkout flow because 68% cart abandonment is becoming a problem and your paycheck has been 9 days two months in a row. It’s time to take matters into your own hands to beef up the company’s revenue. You know the three-step checkout is the problem. A designer mocks up a simplified single-page flow, but nobody wants to bet the whole revenue stream on a hunch.
You want to show the new checkout to 25% of users, measure the results, and scale up or roll back based on data. Feature Flags’ percentage rollout bucketing is stable: the same user always lands in the same bucket for a given flag, so their experience doesn’t flip-flop between visits.
The Flag
| Property | Value |
|---|---|
| Name | simplified-checkout |
| Type | experiment |
| Enabled | true |
| Rollout % | 25 |
| Rules | (none) |
You don’t need any targeting rules because the rollout percentage handles assignment. Users are bucketed by a consistent hash of their user ID and the flag handle, so the same user always gets the same result for this flag.
Walkthrough
1. Create the flag with name simplified-checkout, type Experiment, enabled, rollout percentage 25. No rules.
2. Branch the checkout template:
{# templates/shop/checkout/index.twig #}
{% set useSimplifiedCheckout = craft.featureFlags.isEnabled('simplified-checkout') %}
{% if useSimplifiedCheckout %}
{% include 'shop/checkout/_single-page' %}
{% else %}
{% include 'shop/checkout/_multi-step' %}
{% endif %}
3. Pass the cohort to your analytics layer so you can measure conversion by group:
{# In your layout or checkout template #}
<script>
window.checkoutCohort = '{{ useSimplifiedCheckout ? "single-page" : "multi-step" }}';
{# Send to your analytics platform #}
analytics.track('checkout_started', {
cohort: window.checkoutCohort,
cartTotal: {{ cart.totalPrice }},
});
</script>
4. Monitor results. After a week of data, the simplified checkout shows a 12% improvement in completion rate. Increase the rollout to 50%, then 75%, then 100%.
5. When you reach 100%, remove the flag check from the template and delete the old multi-step checkout code and deploy the changes to production. The rollout is complete; the new flow is permanent.
You tested a risky checkout change on real traffic without an all-or-nothing deploy. The 75% on the old flow were completely unaffected. The decision was backed by data, and you could have rolled back to 0% in seconds if the new flow had tanked conversions.
3. Zero-Downtime Maintenance Mode #
Your payment gateway has notified you of scheduled maintenance this Saturday from 2:00 – 4:00 AM. Checkout will fail during that window. The rest of the site should stay up.
You could deploy a code change to disable checkout, then deploy another to re-enable it. Or you could set a flag that ops can toggle from the control panel without touching code or waking up a developer. This is the textbook use case for an ops flag: it controls infrastructure behavior, not a feature release.
The Flag
| Property | Value |
|---|---|
| Name | checkout-maintenance |
| Type | ops |
| Enabled | false (flip to true when maintenance starts) |
| Rollout % | 0 |
| Rules | environment = production |
Walkthrough
1. Create the flag with name checkout-maintenance, type Ops, disabled. Add an environment rule with value production so it only takes effect on the production server — your staging and dev environments continue working normally.
2. Add a maintenance check to your cart and checkout templates:
{# templates/shop/_includes/checkout-guard.twig #}
{% if craft.featureFlags.isEnabled('checkout-maintenance') %}
<div class="maintenance-banner">
<p>Our payment system is undergoing scheduled maintenance.
Checkout will be available again shortly. You can continue
browsing and your cart will be saved.</p>
</div>
{% endif %}
3. Gate the checkout button:
{# templates/shop/cart.twig #}
{% if craft.featureFlags.isEnabled('checkout-maintenance') %}
<button disabled class="btn btn--disabled">
Checkout Temporarily Unavailable
</button>
{% else %}
<a href="{{ url('shop/checkout') }}" class="btn btn--primary">
Proceed to Checkout
</a>
{% endif %}
4. Saturday at 1:55 AM: Your ops team member opens the control panel, navigates to Feature Flags, and toggles checkout-maintenance to enabled. Checkout is disabled. No deploy. No SSH. No developer paged.
5. Saturday at 3:50 AM: The gateway confirms maintenance is complete. Toggle the flag off. Checkout is back. Total developer involvement: zero.
6. Leave the flag in place for the next maintenance window. It’s a permanent operational control, not a one-time release toggle. The audit log records who toggled it and when — useful for post-incident reviews.
A 2 AM deployment became a control panel toggle, and the audit log has a clean record of the whole thing for the next retrospective.
4. Beta-Test a Premium Feature #
Audience: Commerce + product teams
A new customer dashboard is in the works for premium subscribers: order history, saved payment methods, loyalty points. Big feature. 2,000 premium subscribers. And you don’t want all of them hitting it on day one.
The plan is to beta-test with a hand-picked group of 20 power users first, gather feedback, fix rough edges, and then open it up to everyone on the premium plan. That means layered targeting — first gate by user group, then later by subscription plan. The permission flag type signals that this flag controls access to a capability, not a release or an experiment.
The Flag
| Property | Value |
|---|---|
| Name | customer-dashboard |
| Type | permission |
| Enabled | true |
| Rollout % | 0 |
| Rules | userGroup = beta-testers |
Later, replace the rule with: subscriptionPlan = premium
Walkthrough
1. Create a beta-testers user group in Craft’s Settings > Users > User Groups. Add your 20 selected beta users to this group.
2. Create the flag with name customer-dashboard, type Permission, enabled. Add a rule: userGroup = beta-testers.
3. Gate the dashboard navigation item so only flagged users see it:
{# templates/_layouts/_account-nav.twig #}
<nav class="account-nav">
<a href="{{ url('account/orders') }}">Orders</a>
<a href="{{ url('account/addresses') }}">Addresses</a>
{% if craft.featureFlags.isEnabled('customer-dashboard') %}
<a href="{{ url('account/dashboard') }}">Dashboard</a>
{% endif %}
</nav>
4. Optional: Protect the dashboard route so someone cannot navigate directly to it. Your call if this worthwhile or not.
5. Collect feedback. Beta testers use the dashboard for two weeks. You fix bugs and polish the UI based on their input.
6. Open it up to all premium subscribers. In the control panel, edit the flag. Remove the userGroup = beta-testers rule and add subscriptionPlan = premium. Every active premium subscriber now has access. The beta-testers group can be cleaned up later.
7. Eventually, make it generally available. Remove all rules so the flag is globally enabled. Or keep the subscriptionPlan rule if the dashboard should remain a premium-only feature permanently — the permission flag type is designed for exactly this kind of long-lived access control.
You beta-tested with a small group, iterated on real feedback, and expanded access gradually without redeploying. “Who can see this” and “is the code deployed” were cleanly separated, which meant your dev and release cycles were fully decoupled.