How to choose between circuit breakers and feature flags

Alex Casalboni

Alex Casalboni

Developer Advocate

September 22, 2026

  • A circuit breaker is an in-process resilience pattern that protects one call path. It reacts fast and automatically, but changing its behavior means changing code.
  • Feature flags give you runtime control. A kill switch turns off one behavior without a deploy, and progressive rollout limits blast radius before a failure happens.
  • Impact metrics and safeguards in Unleash turn a metric condition into an automated stop condition around a release. Signals and actions can react to events from your monitoring tools.
  • Design the fallback and the safe default first. Invert the kill switch flag so off is the safe state, and rely on local evaluation so the switch works when systems struggle.
  • In financial services, scope switches narrowly, require dual control, and keep audit logs, because the control is also a governance instrument.

Failures in distributed systems are routine. A payment provider slows down, a new release misbehaves for one customer segment, or a downstream service starts returning errors. The question is which layer responds.

Production failure is becoming the norm, and the goal shifts from pure correctness to containment and reversibility. You can respond with an in-process circuit breaker or with runtime control built from feature flags, impact metrics, and safeguards.

The decision point is who needs to change behavior, how fast, and without a deployment. The circuit breaker lives in the code that makes the call. Feature flags and automation live around it as a control layer.

Read our FeatureOps Whitepaper
Get your free copy and learn how to connect engineering performance to business outcomes for fun and profit.Download now

What a circuit breaker does, and where it stops

A circuit breaker stops calls to a failing dependency and serves a fallback instead. It belongs to a family of graceful degradation techniques that includes timeouts, bulkheads, retries with backoff, and load shedding. The circuit breaker protects a single call path.

The strength of the pattern is where it runs. It reacts inside the process where the call happens, so the reaction happens without human steps. For a fast, local reaction to a failing call, that is the right place for the logic.

The limit comes from the same property. The logic is hard-coded. Suppose you need to disable a risky integration for one customer segment, choose a different fallback during an incident, or stop a release that is hurting several services at once. With a circuit breaker alone, you have to change the code and deploy.

Without runtime control, your business owners cannot change system behavior when impact demands it.

What feature flags add at runtime

A kill switch is a feature flag whose only job is to turn off a piece of production behavior without a deploy. Compare that with a rollback. A rolling deployment takes minutes at best, and longer with a large fleet or a database migration. A kill switch turns off one feature while everything else in the release keeps running.

Feature flags also work before a failure happens. Targeting and progressive rollout limit blast radius by exposing a change to a small segment first, then widening exposure as confidence grows.

The difference between canary releases and kill switches is timing. A kill switch reacts after a problem appears. A canary release limits exposure up front by testing with a small subset of users.

The two layers also overlap. Kill switches are typically implemented as configuration flags or circuit breakers, and they can be triggered manually or automatically from predefined metrics and thresholds.

You are deciding whether the decision sits inside the call or in a control layer around it.

The decision point: resilience pattern or runtime control

Ask four questions about any failure you want to handle.

Question

Circuit breaker

Feature flag control

Where does it run?

In the calling code

Around the dependency or release

Who changes it?

Code owners, through a deploy

Operators or automation, through a flag change

What is the scope?

One call path

A feature, segment, environment, or whole release plan

How does it react?

Automatic, in-process reaction

Reactive stop (kill switch) or proactive limiting (progressive rollout, canary)

Use the in-process pattern when the failure is local to a call and needs a fast automatic fallback. Use feature flags when you need a deliberate switch, a gradual exposure, or a stop condition tied to a metric that spans services.

Or use them together:

const { initialize } = require('unleash-client');
const CircuitBreaker = require('opossum');

const unleash = initialize({
  url: process.env.UNLEASH_URL,
  appName: 'payments-service',
  customHeaders: { Authorization: process.env.UNLEASH_API_TOKEN },
  bootstrap: { filePath: './unleash-bootstrap.json' }, // safe state if Unleash is unreachable at startup
});

unleash.impactMetrics.defineCounter('fraud_v2_fallbacks_total', 'Payments the new fraud provider did not score');

// In-process: the breaker protects this one call path and reacts in milliseconds.
const breaker = new CircuitBreaker(callNewFraudProvider, {
  timeout: 2000,
  errorThresholdPercentage: 50,
  resetTimeout: 30000,
});
breaker.on('fallback', () => unleash.impactMetrics.incrementCounter('fraud_v2_fallbacks_total'));
breaker.fallback((payment) => legacyRulesScore(payment));

async function scorePayment(payment, context) {
  // Runtime control: off means the legacy path.
  // And a safeguard on the metric above can turn it off.
  if (!unleash.isEnabled('fraud-provider-v2', context)) {
    return legacyRulesScore(payment);
  }
  return breaker.fire(payment);
}

Both layers depend on fallback design, and you should choose the fallback before the incident. Options include the previous implementation, a cached or static response, hiding the feature, or a queue. A queue fits only where delay is tolerable.

How to add automated stop conditions around a dependency or release

Make “off” the safe state

Start with the flag convention. Invert the flag so off is the safe state: the flag stays disabled while the feature works, and enabling it turns the feature off.

Name flags so anyone reading an alert at 2am knows what flipping them does. A name like disable-checkout-v2 is clearer than checkout-flag-3.

Then plan for the flag service being unreachable.When using Unleash, Backend SDKs evaluate feature flags locally and keep serving the last known configuration if the flag service cannot be reached. Set safe SDK defaults and bootstrap configuration.

Account for propagation time as well. A 15-second poll interval means up to 15 seconds to reach every instance. If that is too slow for a capability, shorten the interval or stream updates through Unleash Enterprise Edge.

Use impact metrics as the signal

Impact metrics are time-series metrics recorded through the SDK, such as counters, gauges, and histograms. They make the data part of the rollout logic, so a release plan can pause, or the flag can turn off, when a metric crosses a threshold.

Two examples: pause a rollout when error rates cross a threshold, or track p95 latency during a gradual rollout. The Node.js, Java, Go, Python, Ruby, and .NET SDKs can record impact metrics. The PHP and Rust SDKs do not, so check the SDK compatibility table before you design around them.

You can also use metrics you already collect. A Prometheus or VictoriaMetrics instance can serve as an external source. The data stays in your system and is queried at read time, not ingested or stored.

Use safeguards and signals for the stop

Safeguards turn a metric into a stop condition. You attach a safeguard to a feature flag in a specific environment, pick a metric, set a condition, and choose an action. Safeguards that read your existing Prometheus metrics follow that pattern.

One example from the Prometheus integration uses checkout_errors_total as a count, a condition of more than 10 in the last 15 minutes, and the action Pause release plan automation. Treat it as an illustration of the structure. Set your own values from your traffic and risk tolerance.

That example pauses release plan automation. The other action, Disable environment, turns the flag off in that environment. Connected SDKs pick up the change on their next refresh.

Signals and actions extend the idea to events outside the flag service. Signals represent events in external systems, and actions are the automated responses to them. Tools such as Datadog, Dynatrace, and Grafana could post to a signal endpoint.

Considerations for financial services

Regulatory focus in financial services has shifted from recovery objectives to response and containment, so limiting damage quickly carries more weight than it did when recovery objectives led.

Knight Capital lost more than $460 million in August 2012 after a deployment error reactivated dormant code and sent millions of erroneous orders in about 45 minutes. That shows the cost.

DORA became applicable in January 2025, and it expects firms to contain incidents without delay. Confirm with your compliance team which regulations apply to your firm.

Several design choices follow for kill switches in financial services:

  • Scope each switch to the smallest logical unit of risk, so operators do not hesitate to use it.
  • Evaluate switches locally so they keep working during network partitions. During a partition, the switch keeps working on its last known state, and a new change needs connectivity to propagate.
  • Require the four-eyes principle for changes, with a pre-approved break-glass path for on-call engineers, because the switch is itself an attack vector.
  • Keep immutable audit logs of every change.

Conclusion

Keep the circuit breaker for local, automatic protection of a call path. Add feature flags, impact metrics, and safeguards for runtime control and automated stop conditions around a dependency or a release. The circuit breaker owns the failing call. Feature flags and safeguards own the feature or release.

Unleash is an enterprise FeatureOps platform with an open core and provides runtime control over how software behaves in production, including feature flags, progressive delivery, governance, and auditability.

Try runtime control around one dependency

Pick one dependency or release where a deploy is too slow a response, and add a kill switch with a safe default around it. Your circuit breakers keep protecting the call path, and the feature flag gives your team a deliberate way to change behavior.

Start a free trial of Unleash to see how that control layer fits alongside the resilience patterns you already run.

FAQs

What is the difference between a circuit breaker and a feature flag?

A circuit breaker is an in-process pattern that stops calls to a failing dependency and serves a fallback. A feature flag is a runtime control that lets operators or automation change behavior without a deploy.

Is a kill switch the same as a circuit breaker?

They overlap. Kill switches are typically implemented as configuration flags or circuit breakers, triggered manually or automatically from predefined metrics and thresholds. The practical difference is whether the decision sits inside the call or in a control layer around it.

When should you use a circuit breaker instead of feature flags?

Use a circuit breaker when the failure is local to a call and needs a fast automatic fallback. Use feature flags when you need a deliberate switch, a gradual exposure, or a stop condition that spans services. Most teams need both.

How do you make a kill switch safe to use during an incident?

Invert the flag so off is the safe state, and name it so its effect is obvious. Set safe SDK defaults. Backend SDKs evaluate locally and keep serving the last known configuration if the flag service is unreachable.

How do impact metrics and safeguards create automated stop conditions?

Impact metrics record time-series data from the SDK, so a release plan can pause, or the flag can turn off, when a metric crosses a threshold. Safeguards attach a metric, a condition, and an action to a feature flag in an environment. Any threshold you choose should reflect your own traffic and risk tolerance.

What should financial services teams add to a kill switch design?

Scope each switch to the smallest logical unit of risk, evaluate locally so it works during network partitions, require dual control, and keep immutable audit logs. The control is itself a governance instrument.