Sign up for "Implementing a Kill Switch for AI" on Sep 22nd

Events

Join the Unleash team to learn how to integrate runtime control in your AI strategy.

Operational feature flags: runtime controls for financial services

Alex Casalboni

Alex Casalboni

Developer Advocate

September 24, 2026

In June 2025 a Google Cloud change rolled out worldwide in seconds and took a large part of the internet down with it. The first remediation in the postmortem was feature flag protection for new code paths. Five months later, Cloudflare went dark for hours over a bot management configuration file, and their postmortem committed to more global kill switches.

The shared lesson: you need a way to change how production behaves without shipping code.

Unleash runs the runtime control layer at Visa, Lloyds Bank, and Prudential, and what follows are the operational techniques that keep coming up in our conversations with platform and SRE teams at large regulated organizations, grouped by who owns the problem.

Resilience and reliability

The platform team usually ends up owning this group, and that is the right outcome. Every control below is worth building once and handing to every service that needs it. A dozen teams each inventing their own resilience mechanisms leaves you with a dozen behaviors to reason about at 3am and no way to move them together.

Third-party dependency kill switches

A typical retail bank’s request path runs through a long list of other people’s systems:

  • Market data from Bloomberg or LSEG
  • Account aggregation through Plaid or Tink
  • Credit bureau calls to Experian, Equifax, or TransUnion
  • Identity verification through Jumio, Onfido or Socure
  • Fraud scoring from Feedzai or Sift
  • Address lookup from Loqate
  • One-time passcodes through Twilio
  • Card authorization over the Visa and Mastercard rails
  • Payment messaging over Swift

Every one of those has a maintenance window, a rate limit and an occasional bad day, and almost none of them are inside your control.

The Digital Operational Resilience Act (DORA) already makes you keep a register of ICT third-party providers. A kill switch per vendor turns that register into something executable: for each entry you need a flag, a documented fallback, and a policy for what happens when the call fails.

That policy is the interesting bit, because it differs by vendor. Address verification can fail open and let the payment through with a review marker. On the other hand, sanctions screening must fail closed. And credit bureau timeouts might route to a queue for manual assessment. Putting the policy in a variant payload means you can change it during an incident without shipping code to twelve services.

In Unleash:

  • One Kill Switch flag per vendor, tagged to match the entry in your third-party register
  • Strategy variants with payloads carrying the fallback policy, changeable at runtime
  • Constraints on market or product line, because the right fallback in one jurisdiction is the wrong one in another
  • Change requests with four-eyes approval for anything that relaxes a control
  • Audit logs answering when the switch was thrown and by whom, which is the evidence an operational resilience review will ask for

Selective load shedding

Shedding at the load balancer is blind by design. Flag-based shedding is deterministic per identity: bucket on customer ID or session ID and the same person gets a consistent experience for the whole outage rather than a mix of served and rejected requests that produces broken multi-step flows and retry storms.

Once you are shedding in the application, you can shed by meaning. Drop background balance refreshes before customer-initiated payments. Protect branch and call-center channels while degrading a polling integration. Defer rather than reject wherever the work can be queued and accepted asynchronously, which is a far better experience than a 503.

Keep the trigger where it belongs. Queue depth, p99 latency and error rate already live in your monitoring stack, and they’re the right signals to decide when to shed. Unleash decides who and what, which is the part infrastructure cannot answer.


UnleashContext ctx = UnleashContext.builder()
    .userId(request.getCustomerId())
    .addProperty("channel", request.getChannel())
    .addProperty("transactionType", request.getType())
    .addProperty("customerTier", request.getCustomerTier())
    .build();

if (unleash.isEnabled("shed-non-critical-reads", ctx)) {
    return cachedBalance(request.getCustomerId());
}
return coreBanking.fetchBalance(request.getCustomerId());

In Unleash:

  • Gradual rollout strategy with stickiness on userId or sessionId, so a shed percentage lands on a stable set of people
  • Constraints on custom context fields such as channel, transaction type, and customer tier
  • Reusable segments so “institutional flow” or “branch traffic” is defined once and applied across every service
  • Strategy variants to express shed severity rather than a single on/off
  • Backend SDKs evaluate in-process, so a shed decision costs no network call on a path that is already struggling, and Unleash Enterprise Edge gives frontend SDKs the same property

Graceful degradation ladders

Load shedding is one rung on a longer ladder. Above it sit the cheaper moves: turn off recommendations, drop search facets, serve a five-minute-old balance instead of a live one, stop generating PDFs on demand, suppress the analytics beacon. Each of those buys capacity at a known cost to the experience, and you should decide in advance in which order, rather than argue about it at 2am. We covered the engineering patterns behind this in graceful degradation in practice.

The pattern worth adding here is a single dial. For example, “criticality” is a static property of a code path (or an endpoint). The team that owns the recommendations widget already knows it is deferrable, and that answer does not change during an incident, so they hardcode its criticality as a context value. It’s one line in the evaluation context, decided once, reviewed in a pull request like anything else. Remember: criticality is a property of the code, severity is a property of the incident.

The part that moves lives in Unleash: one shared flag with a constraint on that criticality value. At the first sign of trouble the SRE team sets the constraint to “deferrable” and 40 services drop their optional work at once. If that is not enough, they widen it to include “non-essential”, then “important”. Application teams never have to reason about the global picture, and the incident commander gets one lever instead of a spreadsheet of flag names.


UnleashContext ctx = UnleashContext.builder()
    .addProperty("criticality", "deferrable") // statically defined by each dev team
    .build();

if (unleash.isEnabled("graceful-degradation", ctx)) {
    return Recommendations.fallback();  // a static list
}
return recommender.forCustomer(request.getCustomerId());

In Unleash:

  • A custom context field for criticality, set as a constant by the team that owns each code path, with a constraint on the shared degradation flag that the SRE team widens as severity rises
  • The Operational and Kill Switch flag types plus tags, so degradation controls are filterable and distinct from release flags
  • Constraints on appName, which every SDK reports automatically, so the SRE team can carve out or exclude one misbehaving service without anyone touching code
  • Impact metrics feeding safeguards, so a rung can trip on its own when latency crosses a threshold
  • Change requests to govern who can move the whole estate to a higher severity

Regional evacuation and DR control

Draining a region is mostly a routing problem until you reach the parts that routing cannot express. For example, which workloads follow, which ones stay pinned for data residency reasons, whether writes go read-only during the failover window, and how fast you let traffic back in afterwards. Cold caches and connection storms mean the ramp back is often more dangerous than the evacuation.

By involving feature flags, you can control a percentage rollout gradually: start with 5%, watch, raise to 20%, watch, raise to 60%, and so on. As a regulated firm, you have to run DR exercises on a schedule anyway, so this control gets exercised whether you like it or not, and the audit trail from those exercises doubles as evidence.

So what happens when the flag system itself is in the region you are evacuating? You need local evaluation inside the SDK, a last-known-good cache, bootstrapped defaults on cold start, and Edge nodes that spread across regions.

In Unleash:

  • Constraints on a region or datacenter context field, with reusable segments per region
  • Gradual rollout for the ramp back, sticky so returning users stay put
  • Scheduled change requests for planned failover windows
  • Unleash Enterprise Edge across 35+ cloud regions, or self-hosted Edge in your own failure domains, so the control plane is not inside the blast radius of the thing it is controlling
  • Audit logs and change request history as the artifact you hand to whoever reviews the exercise

Chaos and fault injection

Severe-but-plausible scenario testing is now a regulatory expectation, which means chaos engineering should have a real budget line. The blocker is often blast radius: nobody will sign off on injecting latency into a production payment path if the only scope control is a deploy.

Wrapping the injection in a flag gives you a scope control for the risk committee to review. These flags can be time-boxed and removed after the exercise. For example:

  • Target 0.5% of internal test accounts
  • Put the injected latency in a variant payload so you can raise it from 200ms to 2s without a release
  • Wire the abort to a safeguard so the experiment stops itself if the error rate moves before a human notices.

In Unleash:

  • A dedicated project for injection flags with RBAC restricting production enablement to a named group
  • Reusable segments limiting experiments to synthetic or internal accounts
  • Variants carrying injection parameters (latency, error rate, dropped connection)
  • Impact metrics and safeguards to auto-abort on threshold breach
  • Audit logs recording the exact experiment window, which is what makes the results defensible

Risk, fraud and security

Fraud operations measures itself in time-to-mitigate, and today that clock usually includes a deployment.

Risk posture dials

When a credential stuffing wave or a card testing run starts, the response is a set of tightenings:

  • force step-up authentication on the affected channel
  • lower per-transaction limits
  • block new payee creation for accounts younger than 30 days
  • extend settlement holds
  • disable the API path being abused

Most institutions implement these as configuration changes that require a release, or as buttons inside a vendor console that only covers that vendor’s slice of the problem.

Expressed as variants in Unleash, the posture becomes a dial with named positions rather than a pile of independent booleans. For example, “normal”, “elevated”, and “defensive”. Each position carries the thresholds and the required friction, and fraud operations move the dial in seconds with a full record of why.

In Unleash:

    • Strategy variants representing posture levels, with payloads carrying limits and thresholds
    • Constraints on context fields for channel, device risk score, ASN, account age and geography
    • Reusable segments for the cohorts you keep coming back to, such as recently opened accounts
  • A scoped RBAC role giving fraud operations control of exactly these flags and nothing else
  • Change requests with a break-glass path, so routine tightening is reviewed and emergency tightening is not blocked

Order flow kill switches

SEC Rule 15c3-5 already requires broker-dealers to be able to halt order flow immediately, so most trading firms have built this once, bespoke, inside the order management system. It is well tested and it covers exactly one system.

The shape is simple, and the important part is the default:


context = {
    "userId": order.desk_id,
    "properties": {
        "instrument": order.instrument_class,
        "venue": order.venue,
    },
}

# With no cached state, halt rather than let orders through.
if unleash.is_enabled("order-flow-kill-switch", context, fallback_function=lambda feature, ctx: True):
    raise OrderFlowHalted(order.desk_id, "kill switch engaged")

oms.submit(order)

The useful question is what else in the estate deserves the same treatment and currently does not have it. For example, new model versions in a credit decision path, agentic workflows that were granted write access to a ledger, or an automated pricing engine.

We wrote about that pattern for AI systems specifically in securing AI agents starts with a kill switch you control. Can you turn it off in seconds without deploying? Who approves that? Would the audit trail satisfy a regulator? Who controls the kill switch system itself?

In Unleash:

  • Kill Switch flag type with an owner and a runbook reference recorded against it
  • Four-eyes change requests for arming and disarming, with a documented break-glass role
  • Instant rollback by button or API, callable from a runbook or a bot
  • Constraints on desk, instrument class and venue, so a halt can be as narrow as one strategy or as wide as the firm
  • Self-hosting or a single-tenant private instance where the control has to live inside your own authorization boundary

Cost and capacity

Nobody buys a feature flag platform to cut cloud spend, but these two show up in the business case once the resilience conversation is already underway.

Observability sampling control

Telemetry is frequently one of the largest line items in the cloud bill and the sampling rate is usually baked into a config map that ships with the service. Moving it behind a flag gives you a dial per service. During an incident you want to raise sampling on the 3 services involved and leave everything else alone, which is exactly the targeted change that a global config value cannot express.

In Unleash:

  • Variant payloads carrying sample rates, read by the instrumentation layer at runtime
  • Constraints on service name and environment, so one flag governs the whole estate at per-service granularity
  • Gradual rollout when you want to sample a percentage of traffic rather than switch wholesale
  • Impact metrics to confirm you have not lost the signal you need

Mainframe offload

Core banking capacity is metered and billed, and unfortunately it does not autoscale. When a traffic peak arrives, the levers available are usually to buy more MIPS or to let queues build. A third option is to route eligible reads to a replica or cache and keep the mainframe for the work that genuinely needs it.

That routing decision has to be conditional, because not every read tolerates staleness. Balance display on a mobile app usually can, but a pre-authorization check cannot. Encoding the eligibility rule as a flag with constraints means the boundary is reviewable and adjustable during a peak.

In Unleash:

  • Gradual rollout on the offloaded read path, sticky so a customer does not flip between fresh and cached within a session
  • Constraints on transaction type and staleness tolerance
  • Impact metrics tracking latency and cache age against the offload percentage

Compliance and market operations

The controls here are rarely triggered by an incident. They move when a regulator, a legal team or a geopolitical event says they have to move, often with a deadline attached and always with someone asking afterwards when the change took effect.

Jurisdictional gating

One codebase serving 40 markets means forty sets of rules about what may be shown, sold, stored or processed. A product cleared in Germany may still be waiting on approval in Poland. Cooling-off periods differ, data residency constraints differ, and so on. Most organizations end up with a mixture of environment variables, database configuration and a few well-intentioned if statements, spread across services and with no particular owner.

Sanctions response is the case that makes this urgent. The measures that followed Russia’s invasion of Ukraine in 2022 arrived almost daily for weeks, and each one carried its own scope and its own deadline. The EU adopted the SWIFT exclusions on March 2 with effect from March 12, while OFAC ran separate wind-down licences with different end dates per institution. Every one of those changes had to land across the estate on the right date, in the right jurisdiction, with a record showing exactly when it took effect. That is a release-management problem wearing a compliance hat.

In Unleash:

  • Reusable segments defining each jurisdiction once, by any combination of context fields
  • Constraints on market, product line, and entity, applied consistently across every service
  • Projects with granular RBAC so a regional compliance owner controls their own market without touching anyone else’s
  • Audit logs answering when a market was gated and on whose authority, which is the question that gets asked afterwards
  • Scheduled change requests so a restriction with a known effective date goes live on that date, reviewed in advance

Open banking traffic prioritization

Third-party provider traffic under PSD2 and the UK open banking rules can be a large and extremely bursty share of a bank’s API volume, much of it aggregators polling for changes rather than customers doing anything. You are obliged to serve it, and you are obliged to serve it without discriminating against TPPs in favor of your own channels.

Those two obligations pull against each other when capacity gets tight. The resolution is a documented, auditable prioritization policy rather than a hand-tuned rate limiter. That means per-TPP quotas, a lower priority for background polling than for customer-initiated payment flows, and a record showing that the policy was applied consistently.

In Unleash:

  • Constraints on the TPP client identifier and the consent type carried in the request
  • Reusable segments grouping TPPs into tiers, so policy changes apply to a class rather than to individuals
  • Variants carrying per-tier quotas, adjustable without a release
  • Audit logs demonstrating that you applied throttling evenly, which is the evidence a non-discrimination complaint will turn on

What these flags need, compared to release flags

Every flag in this article is permanent. It has an owner on a rotation, an entry in a runbook, and a last-tested date. It will still be there in four years.

Exercise them. A switch nobody has activated in 18 months has an unknown state. Schedule the drills and record the results. A failed drill becomes an incident. Regulators reviewing an operational resilience program will ask when you last tested, and the honest answer needs to be recent.

Pre-authorize the runbook. Flipping a shed flag mid-incident cannot wait for a change advisory board, and the answer to that is not to bypass governance. Approve the blast radius in advance, define which flags are break-glass, require four-eyes on the ones where the risk warrants it, and let the audit trail carry the accountability after the fact. Trading desks have run kill switches this way for years.

Make the control plane boring. The first question any serious architect asks is what happens when the flag system is unreachable during the incident. Local evaluation with no network call in the request path, last-known-good caching, bootstrapped defaults, Edge nodes in separate failure domains, and self-hosting where the authorization boundary demands it.

Document who gets degraded. Selective degradation means someone is chosen to have a worse day. If you protect institutional flow by throttling retail, expect to justify that under consumer duty rules or a service level agreement. Write the targeting logic down and put it through the same review as any other policy.

Do not ask application teams to care about load shedding. They will not. Ask them two answerable questions instead: which of your endpoints are shed-eligible at which criticality, and what should happen to a request you drop. Most large institutions have already produced a version of that mapping for their important business services and it is sitting in a spreadsheet somewhere. The platform team owns the triggers, the criticality dial and the paved-road SDK wrapper. Then application teams get resilience by adoption rather than by effort.

Unleash is the FeatureOps platform used by financial institutions including Visa, Lloyds Bank and Prudential to control how software behaves in production. If you are working through any of the techniques above, we would like to help.