Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Feature Flags and Progressive Delivery

By Kokil Thapa | Last reviewed: September 2026

Shipping a big release on Friday still breaks production for too many teams. Feature flags and progressive delivery separate deployment from release so you merge code early, keep it dormant, and turn it on for a small slice of users first. On production Laravel applications I maintain, flags have saved hours that would otherwise go to hotfix deploys. This guide covers the patterns, Laravel Pennant on PHP 8.3+, rollout steps, and the mistakes that cause flag debt.

What are feature flags and how do they enable progressive delivery?

A feature flag is a runtime switch that decides whether a code path runs. Progressive delivery uses those switches to expose new behaviour in controlled steps. You ship the code to production behind a flag. You then widen the audience while watching errors, latency, and business metrics.

Think of three separate events:

  • Deploy — new code reaches servers (Git push, CI, symlink swap).
  • Release — users can actually use the new capability.
  • Rollout — the release expands from internal staff to beta users to everyone.

Without flags, deploy and release happen at the same moment. One bad assumption affects every visitor. With flags, deploy becomes boring and release becomes a deliberate product decision.

Progressive Delivery PipelineCommitGit + CIDeployFlag OFFInternalStaff onlyCanary5% usersFull Rollout — Flag ON for 100%Monitor metrics at each stageKill SwitchInstant OFF, no redeployObservabilityLogs + APM + alertsFlag CleanupRemove dead branches
Feature flags and progressive delivery split deploy from release and add a kill switch at every stage.

Common flag types map cleanly to delivery goals:

Flag typePurposeTypical lifetimeProgressive delivery role
Release flagHide incomplete featuresDays to weeksCanary and percentage rollout
Ops flagKill switch, maintenance modePermanentInstant rollback without redeploy
Experiment flagA/B test variantsWeeksMeasure conversion before full release
Permission flagEntitlements, plan tiersLong-livedGradual access by customer segment

For deeper Laravel-specific setup, see the dedicated Laravel Pennant feature flags implementation walkthrough. Small teams should also read feature flag rollout for small teams before buying enterprise tooling.

How do you implement feature flags in Laravel 13?

Laravel Pennant ships with Laravel 12 and remains the first choice for PHP teams on Laravel 13. It stores flag state in the database or Redis. You define features in a service provider and evaluate them in controllers, Blade, or middleware.

Install and define a feature

On Laravel 12+, Pennant is included. Publish the migration and define your first feature:

php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider"
php artisan migrate
<?php
/* app/Providers/AppServiceProvider.php */

use App\Models\User;
use Laravel\Pennant\Feature;

public function boot(): void
{
    Feature::define('new-checkout-flow', function (User $user) {
        if (app()->environment('local', 'staging')) {
            return true;
        }

        return $user->isInternalTester();
    });
}

Evaluate in application code

Never branch only in Blade. Always enforce business rules on the server.

<?php
/* app/Http/Controllers/CheckoutController.php */

use Laravel\Pennant\Feature;

public function show(Request $request)
{
    if (Feature::active('new-checkout-flow')) {
        return view('checkout.v2', [
            'cart' => $request->user()->cart,
        ]);
    }

    return view('checkout.legacy', [
        'cart' => $request->user()->cart,
    ]);
}

In Blade, Pennant directives keep templates readable:

@feature('new-checkout-flow')
    @include('checkout.partials.v2-summary')
@else
    @include('checkout.partials.legacy-summary')
@endfeature

Percentage rollout with Pennant

For progressive delivery, combine Pennant with a stable hash so the same user always gets the same variant:

Feature::define('new-checkout-flow', function (User $user) {
    if (Feature::value('new-checkout-flow') === 'force-on') {
        return true;
    }

    if (Feature::value('new-checkout-flow') === 'force-off') {
        return false;
    }

    $bucket = crc32($user->id . 'new-checkout-flow') % 100;

    return $bucket < (int) Feature::value('new-checkout-flow-percentage');
});

Activate for 5% from Artisan or a small admin panel:

php artisan pennant:activate new-checkout-flow --value=5

Official reference: Laravel Pennant documentation. Pair flag checks with Laravel feature testing best practices so both paths stay covered in CI.

Pennant Evaluation FlowHTTP RequestMiddlewareResolve userPennantCheck flagCacheFlag ON PathNew controller + viewFlag OFF PathLegacy behaviourResponse — same URL, different code pathLog flag name + outcome for observability
Laravel Pennant resolves feature flags at request time with cache-backed storage for progressive delivery rollouts.

What is the difference between feature flags and blue-green deployments?

Blue-green and canary deployments change which version of the entire application runs. Feature flags change behaviour inside a single running version. They solve different problems and work best together.

Blue-green swaps traffic between two full environments. Rollback means routing back to the old stack. That still takes minutes and may require database compatibility between versions.

Feature flags flip one behaviour inside the current deployment. Rollback is a config change. On a booking portal I shipped with Livewire, a payment-step flag let us disable a new Khalti flow in seconds when a gateway callback format changed.

Kubernetes teams often combine both. Progressive delivery with Argo Rollouts handles pod-level traffic splitting. Pennant handles user-level logic inside PHP. The feature branch deployment workflow article covers how Git strategy fits this model.

Deploy Strategy vs Feature FlagsInfrastructure RolloutBlue-green, canary podsSwaps entire app versionRollback: route trafficFeature FlagsPennant, LaunchDarklyToggles code pathsRollback: flip switchBest Practice: Use Both LayersDeploy safely with CI + zero-downtime releasesRelease gradually with per-feature flagsKill bad features without rolling back deploy
Infrastructure rollouts and feature flags and progressive delivery complement each other at different layers of the stack.

How do you roll out a feature safely with progressive delivery?

A repeatable rollout beats ad-hoc toggling. Use this sequence on every non-trivial feature.

  1. Define success metrics before coding. Pick error rate, p95 latency, conversion, or support tickets. Without a baseline, you cannot judge the rollout.
  2. Ship dark. Merge behind a default-off release flag. Run automated tests for both paths. Validate in staging with the flag forced on.
  3. Enable for internal users. Staff accounts or a allow-list email domain see the feature first. Fix obvious bugs before external exposure.
  4. Canary by percentage. Move 1%, then 5%, then 25%, then 50%, then 100%. Wait at each step until metrics stay stable.
  5. Watch payment and auth paths closely. These flows fail quietly until revenue drops. Add structured logging with the flag name in every branch.
  6. Remove the flag. After full rollout and a soak period, delete the old path. Flag debt is real technical debt.

On eCommerce work like Quick And Easy Nepalese Grocery, delivery-zone logic rolled out city by city using segment flags tied to postal codes. That limited support load when edge cases appeared.

Ops flags for instant rollback

Keep at least one ops flag per risky integration. Payment gateways, SMS providers, and third-party OCR APIs deserve a kill switch. When Khalti or eSewa changes a callback field, you disable the new handler without reverting Git.

Feature::define('khalti-v2-webhook', fn () => false); /* force off in emergency */

/* In webhook controller */
if (! Feature::active('khalti-v2-webhook')) {
    return $this->handleLegacyKhalti($payload);
}

Document every ops flag in your runbook. Future you will not remember why khalti-v2-webhook exists at 2 a.m.

Observability requirements

Progressive delivery without metrics is guesswork. Minimum viable observability:

  • Log lines include feature_flag and flag_value fields.
  • APM traces tag active flags on the root span.
  • Dashboards split error rate by flag state.
  • Alerts fire when the flagged path error rate exceeds baseline by a set margin.

For JSON log payloads during debugging, the JSON formatter tool helps validate structure before you ship to production log aggregators.

Which feature flag tools fit PHP and Laravel teams in 2026?

Tool choice depends on team size, budget, and hosting model. Most Laravel shops I work with start with Pennant and only add SaaS when product or growth teams need a UI.

ToolBest forStorageApprox. cost
Laravel PennantLaravel 12/13 apps, small to mid teamsDatabase, RedisFree (built-in)
LaunchDarklyMulti-stack orgs, PM-owned rolloutsManaged SaaSFrom ~USD 10/seat/month
Unleash (self-hosted)Teams needing UI + on-prem controlPostgreSQLFree OSS + hosting (~Rs 3,000/month, ~USD 22)
FlagsmithAPI-first products, mobile + webManaged or self-hostedFree tier available
Custom Redis keysLegacy PHP, quick kill switchesRedisFree, high maintenance

Pennant wins when your app is Laravel and your team already runs testing and optimization in CI. LaunchDarkly or Unleash make sense when marketing runs experiments without opening pull requests.

The Martin Fowler feature toggles article remains the best conceptual foundation. For vendor-neutral APIs, review the OpenFeature specification before committing to a proprietary SDK.

WordPress and WooCommerce projects rarely need Pennant. Use a plugin-level flag or a simple option in wp_options. For custom PHP outside Laravel, a Redis hash with TTL and an admin toggle page is enough for ops flags. Do not over-engineer.

Percentage Rollout Stages0%1%5%25%100%Gate: error rate stable 24h before next stepMetrics OKIncrease percentageMetrics BADKill switch ONAfter 100%: remove flag within 2 weeks
Safe progressive delivery increases rollout percentage only when metrics pass gates, with kill switch fallback at every stage.

What mistakes cause feature flag debt on production apps?

Flags help until they accumulate. I've cleaned up flag sprawl on long-running client codebases. These patterns cause the most pain.

Nesting flags inside flags

Three levels of nested if (Feature::active(...)) create combinatorial test paths. One release flag per feature. Compose at the route or controller level instead.

Long-lived release flags

A flag older than two sprints without a cleanup ticket is a forked codebase. Schedule flag removal in the same sprint as full rollout. Your future support and maintenance contract will cost less.

Client-side-only gating

JavaScript that hides a button does not protect the API. Always enforce flags server-side. Public APIs need the same check as Blade templates. See API rate limiting and abuse prevention for related hardening patterns.

No naming convention

Use release-checkout-v2, ops-khalti-webhook, experiment-hero-cta. Prefix by type. Random names like new-thing-2 survive for years and confuse every new developer.

Database migrations tied to flag state

Deploy migrations before enabling the flag, never after. The new code must run against the new schema while the flag is off. On legal-tech portals like Mijar Law Associates, document upload flags followed this order to avoid breaking existing client downloads.

For greenfield work, custom software development projects should include a flag lifecycle section in the technical spec from day one. Retrofitting flags into a monolith without tests is painful.

Key Takeaways

  • Separate deploy from release: ship code with flags off, then turn behaviour on deliberately.
  • Use Laravel Pennant on Laravel 12/13 with PHP 8.3+ for database- or Redis-backed flags without extra SaaS cost.
  • Roll out by percentage with stable user hashing and metric gates at 1%, 5%, 25%, and 100%.
  • Keep ops kill switches for payments, webhooks, and third-party APIs; document them in runbooks.
  • Test both flag paths in CI and delete flags within two weeks of full rollout to avoid permanent forks.
  • Combine infrastructure canaries (Argo, blue-green) with application-level flags for the safest progressive delivery stack.

People Also Ask

Are feature flags the same as A/B testing?

They overlap but serve different goals. A/B testing compares variants to pick a winner using experiment flags. Progressive delivery uses release flags to reduce rollout risk. You can run an A/B test as part of a progressive delivery plan, but not every flag is an experiment.

Do feature flags slow down Laravel applications?

Pennant caches resolved values in Redis or in-memory for the request. A single flag check adds microseconds. Problems appear when you evaluate dozens of flags per request or hit the database on every check without cache. Define flags once per request scope and cache aggressively.

Can you use feature flags without Kubernetes?

Yes. Most Laravel apps I deploy run on Ubuntu with Apache, PHP-FPM 8.3/8.4, and Deployer 7—not Kubernetes. Pennant works on any PHP host. Kubernetes adds pod-level traffic splitting; it is optional, not required for progressive delivery.

When should you remove a feature flag?

Remove release flags within one to two weeks after 100% rollout and stable metrics. Keep ops and permission flags as long as the business rule exists. If removing the flag feels risky, your test coverage for the new path is probably insufficient.

Ship safer releases starting with your next feature

Feature flags and progressive delivery turn release day from a gamble into a controlled process. Start with one release flag on your next Laravel feature, add percentage rollout, and wire basic error-rate monitoring before you widen the audience. The tooling is already in Laravel 13; the discipline is what separates teams that sleep on deploy night from those that do not.

Need help designing flag strategy, Pennant setup, or CI gates for a production app? Review the Adventure Third Pole Trek booking platform in the portfolio, or read Laravel 12 new features for framework context. For hands-on implementation on your stack, contact us about web development or API development—we integrate flags into deploy pipelines, not as an afterthought.

Frequently Asked Questions

Feature flags are runtime switches that decide whether a code path runs. Progressive delivery uses those switches to expose new behaviour in controlled steps: you deploy code with the flag off, then enable it for internal staff, a small percentage, and eventually everyone while watching errors, latency, and conversion. This separates deployment (code reaching servers) from release (users seeing the feature) and gives you a kill switch at every stage.

Without flags, deploy and release happen at the same moment—one bad assumption hits every visitor. With feature flags and progressive delivery, deploy becomes a boring CI push while release becomes a deliberate product decision. Rollout is the third step: expanding from internal testers to beta users to full traffic. You can merge early, keep behaviour dormant, and widen exposure only when metrics stay stable.

Laravel Pennant ships with Laravel 12 and remains the first choice on Laravel 13 with PHP 8.3 or higher. Publish the migration, define features in AppServiceProvider using Feature::define(), and evaluate them in controllers, middleware, or Blade with @feature directives. Store state in the database or Redis. Never branch only in Blade—enforce business rules on the server in controllers and API endpoints so both paths stay protected.

Combine Pennant with a stable hash so the same user always gets the same variant. Use crc32 on the user ID plus flag name, modulo 100, and compare against a percentage value stored in Pennant. Support force-on and force-off overrides for staging and emergencies. Activate from Artisan with pennant:activate and a numeric value, starting at 1% or 5% before widening. Pair this with metric gates at each step.

Blue-green swaps traffic between two full application environments; rollback means routing back to the old stack, which takes minutes and may require database compatibility. Feature flags flip one behaviour inside a single running deployment—rollback is a config change in seconds. They solve different problems and work best together: Kubernetes teams might use Argo Rollouts for pod-level splitting while Pennant handles user-level logic inside PHP.

Define success metrics before coding—error rate, p95 latency, conversion, or support tickets. Ship dark behind a default-off release flag and test both paths in CI. Force the flag on in staging, then enable for internal users. Canary by percentage: 1%, 5%, 25%, 50%, then 100%, waiting at each step until metrics stay stable. Watch payment and auth paths closely. After full rollout and a soak period, delete the flag and old code path.

Most Laravel shops start with Laravel Pennant—free, built into Laravel 12 and 13, backed by database or Redis. LaunchDarkly suits multi-stack orgs where PMs own rollouts, from roughly USD 10 per seat per month. Unleash self-hosted on PostgreSQL is free OSS plus hosting around Rs 3,000 per month (~USD 22). Flagsmith works for API-first products. Custom Redis keys suit legacy PHP kill switches but carry high maintenance. WordPress and WooCommerce projects rarely need Pennant—a wp_options toggle or plugin-level flag is enough.

Laravel Pennant is free and built into Laravel 12 and 13. LaunchDarkly starts around USD 10 per seat per month. Self-hosted Unleash is open source with hosting roughly Rs 3,000 per month (~USD 22). Flagsmith offers a free tier. Custom Redis keys cost nothing beyond existing infrastructure but need ongoing maintenance.

Release flags hide incomplete features for days to weeks and drive canary and percentage rollout. Ops flags are permanent kill switches for maintenance mode or instant rollback without redeploying. Experiment flags run A/B test variants for weeks to measure conversion before a full release. Permission flags control entitlements and plan tiers long-term, enabling gradual access by customer segment. Use one release flag per feature—compose at the controller or route level instead of nesting.

Payment gateways like Khalti and eSewa change callback formats without warning. An ops flag such as khalti-v2-webhook lets you disable a new webhook handler in seconds and fall back to the legacy path without reverting Git. Keep at least one ops flag per risky integration—payments, SMS providers, and third-party OCR APIs. Document every ops flag in your runbook so future you knows why it exists at 2 a.m.

Progressive delivery without metrics is guesswork. Minimum viable observability: log lines include feature_flag and flag_value fields, APM traces tag active flags on the root span, dashboards split error rate by flag state, and alerts fire when the flagged path error rate exceeds baseline by a set margin. Structured logging with the flag name in every branch makes debugging faster. Without a baseline before rollout, you cannot judge whether widening the audience is safe.

Nesting flags inside flags creates combinatorial test paths—use one release flag per feature. Long-lived release flags older than two sprints without a cleanup ticket fork your codebase. Client-side-only gating does not protect APIs; always enforce server-side. Random names like new-thing-2 survive for years—prefix by type: release-checkout-v2, ops-khalti-webhook, experiment-hero-cta. Never tie database migrations to flag state; deploy migrations before enabling the flag so new code runs against the new schema while the flag is off.

They overlap but serve different goals. A/B testing compares variants to pick a winner using experiment flags over weeks. Progressive delivery uses release flags to reduce rollout risk over days. You can run an A/B test as part of a progressive delivery plan, but not every flag is an experiment. LaunchDarkly or Unleash make sense when marketing runs experiments without opening pull requests; Pennant handles both patterns on Laravel apps.

Pennant caches resolved values in Redis or in-memory for the request. A single flag check adds microseconds. Problems appear when you evaluate dozens of flags per request or hit the database on every check without cache. Define flags once per request scope and cache aggressively. For most production Laravel applications on Apache and PHP-FPM 8.3 or 8.4, Pennant overhead is negligible compared to database and external API calls.

Remove release flags within one to two weeks after 100% rollout and stable metrics. Keep ops and permission flags as long as the business rule exists. Schedule flag removal in the same sprint as full rollout—if removing the flag feels risky, your test coverage for the new path is probably insufficient. Flag debt is real technical debt that increases support and maintenance cost over time.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: