Skip to content
Gates

Flag, Switch and Experiment

Each component is one useFlag plus a branch, so exposure is recorded the same way as a hook read. They render on the first frame: until the local snapshot loads, defaultValue decides which branch shows. They render no host element of their own and nest freely.

import { Experiment, Flag, Switch } from "@gates/expo";

<Switch name="payments" fallback={<PaymentsDown />}>
  <Experiment name="checkout-v2">
    <Experiment.Variant control>
      <ClassicCheckout />
    </Experiment.Variant>
    <Experiment.Variant variant="one-tap">
      <OneTapCheckout />
      <Flag name="apple-pay" fallback={<CardButton />}>
        <ApplePayButton />
      </Flag>
    </Experiment.Variant>
  </Experiment>
</Switch>;
ComponentShows while the flag is onShows while offUnknown flag (defaultValue)
<Flag>childrenfallbackoff: new features stay hidden
<Switch>childrenfallbackon: shipped features stay up
<Experiment><Experiment.Variant variant="…"><Experiment.Variant control>off: control

<Flag>

Props: name, fallback? (default nothing), defaultValue? (default false), children. A feature behind a flag.

<Switch>

Same props, but defaultValue defaults to true. A kill switch around a feature that already ships: children stay up until the dashboard disables the flag, then fallback takes over. The difference from <Flag> is only the default, which fails open so a shipped feature keeps working offline.

Switch has the same name as React Native’s toggle. If a file uses both, rename one on import: import { Switch as KillSwitch } from "@gates/expo".

<Experiment>

Two arms of one flag. The assignment is made once in <Experiment> and shared through context, so every <Experiment.Variant> inside agrees, however deep or however many there are, and exposure counts once. Flags are boolean, so an experiment has exactly two arms: control (flag off) and one named variant (flag on). The name labels the code path in your source; the flag decides. The rollout percentage sets the split. Gates records exposure and adoption but does not compute statistics.

<Experiment.Variant> throws if rendered outside an <Experiment>, or without either control or variant.