pattern

Bootstrap Kill Switch

also called Boot-Path Flag, Safe Mode Configuration

A configuration value read from local storage before any application code initialises, paired with a launch-failure counter, so a client that crashes during start-up can still be disabled and recovered.

feature-flagskill-switchcrash-loopclient-configrollback

A flag is enabled for 10% of users, the new code throws during application start-up, and those users see a blank page. Turning the flag off changes nothing for them. The code that fetches fresh flag values runs after initialisation, and initialisation is what crashed, so every reload reads the same cached value and throws again.

This is the general failure of a control that lives inside the thing it controls, and on a client it is severe because there is no operator to intervene: a web page that dies during boot cannot be restarted with different arguments, and a mobile build cannot be recalled from a store.

A bootstrap kill switch is the pattern that closes it: a small configuration value read from local storage as the first thing that happens, before any feature initialises, with the remote fetch updating that cache for the next launch, and a launch-failure counter that lets the client distrust its own cache.

Why it matters

A crash on the boot path is a total outage for the affected cohort, and it is invisible in the usual telemetry. Error monitoring lives inside the application; an application that dies during boot often never reports it, so dashboards show a drop in errors alongside a drop in traffic. The affected users also cannot report the problem through a product that will not load, so the first signal is a support ticket or a revenue graph.

The cohort cannot self-rescue either. A crash loop means the application never lives long enough to complete a network call, which is why any switch that requires the network is not available in the case that matters.

Implementation patterns

  • Read the switch first, from disk. A few hundred bytes with its own parser, before the dependency container, the logger or any feature. Written twice — once properly, once as boring code with its own tests — which is the price of a control that works offline.
  • Emit a "boot started" beacon from inline script before application code, and an "application ready" beacon once interactive. The ratio of the two, segmented by flag variant, is the metric that detects this class in minutes, and it is measurable even when the thing that broke is the application.
  • A launch-failure counter. Increment before boot, clear when ready. On the second or third consecutive failure, ignore cached flags, clear caches and boot a known-good configuration. This is the client-side equivalent of a rollback and on mobile it is the only one available.
  • Fetch flags fresh on boot with a short timeout and a safe default, using the cache for offline rather than as the source of truth, so a bad value cannot pin itself indefinitely.
  • Gate the rollout on the boot-failure signal with an automatic halt, at 1% then 10%. A ramp with no health gate is a schedule.
  • Put flagged code in a lazily-loaded module, so a failure to load it cannot take the application down and the fallback is the previous path.

Industry example

The mobile form of this is standard practice at any company shipping through app stores, because a review queue measured in days makes a client-side recovery path the only rollback. The general lesson has a much older canonical case: in the Knight Capital deployment of 1 August 2012, described in the SEC's 2013 order, a repurposed flag activated dormant functionality on one of eight servers and roughly $460M was lost in about 45 minutes, with no mechanism available that could stop the behaviour quickly. The recurring shape is that the control and the failure shared a fate.

The same pattern appears in server-side systems whose configuration service depends on the platform it configures, and in observability stacks that run on the infrastructure they observe.

Failure scenarios

  • A cached flag pinning a crash, so users are stuck until they clear site data or reinstall.
  • Dashboards that go quiet rather than red, because the failing population cannot report errors.
  • A kill switch evaluated during initialisation, which covers every failure except the one that matters.
  • No launch counter, so the client has no way to distinguish "this configuration is bad" from "the network is slow".
  • A rollout with a schedule instead of a gate, which converts a 10% experiment into a 10% outage for as long as nobody is watching.
  • A safe mode that is never exercised, so its first run in production is also its first test.

Trade-offs

Choose Gains Pays
Disk-cached switch read first Works offline and during a crash loop Duplicated minimal config code, outside your normal stack
Remote-only evaluation One source of truth; instant changes Useless in exactly the failure it exists for
Launch-failure counter with safe mode Stuck clients recover themselves A second code path that must be tested deliberately
Server-side evaluation instead No client cache to poison A request per decision and a cache to invalidate

When not to use it

A flag evaluated on the server, or one gating a feature behind a user action, does not need any of this. Server evaluation means a bad flag produces a bad response the server can simply stop sending, which is a strong argument for keeping risky flags on the server and sending the client a decision rather than the rules. Reserve the bootstrap machinery for the small set of flags that genuinely must be evaluated in the client before the application runs — a rendering mode, a storage migration, a new navigation shell — and keep that set short enough to list.

Interview question

Q: A browser-evaluated flag crashes your application during start-up for 10% of users. Turning it off does not help them. Explain why, and design the mechanism that would have made this a five-minute incident.

What a strong answer covers: that the flag fetch runs after the crash, so the cached value is re-read on every reload; the boot-started and application-ready beacons and their ratio as the detection signal, including why error monitoring cannot see this; the launch-failure counter with a safe-mode boot as the client-side rollback; a health-gated ramp rather than a schedule; keeping flagged code in a lazily-loaded chunk; and the generalisation that a control depending on the code it governs is not a control.

Quick check

Quiz: Why does disabling the flag not rescue a client that crashes during boot? Because the code that fetches new flag values runs after initialisation, so the crash happens before the client can learn the flag changed.

Flashcard: What single counter lets a crash-looping client rescue itself? — A launch-failure count written before boot and cleared when the application is interactive; after two or three failures it ignores cached configuration and boots a known-good default.