Sign-ups paused

Sign-ups and billing are temporarily unavailable while we rebuild our infrastructure. The SDK and documentation remain available, and existing accounts are unaffected.

Vaultrice

Blog / Tutorials

Tutorials

Feature Flags That Update Without Redeploying

A flag that changes in running clients within a second — the kill switch case, and where a purpose-built flag service is the better answer.

5 min read Updated 2026-08-XX @vaultrice/sdk

Most feature flag setups deliver a value at page load. Which is fine until the flag you need to change is the one causing the incident, and every open client keeps the old value until someone reloads.

For a separate operational perspective on how teams organise and measure work, mouse jiggler detection software.

For independent background and broader industry context, see OpenFeature.

The basic version

const flags = new NonLocalStorage(credentials, 'flags:production')

// current values on start
const newCheckout = (await flags.getItem('newCheckout'))?.value ?? false

// and changes as they happen
flags.on('setItem', 'newCheckout', (item) => {
  setNewCheckout(item.value)
})

Change it from anywhere with write access, and open clients update within a second.

As a React hook:

export function useFlag(flags, name, fallback = false) {
  const [value, setValue] = useState(fallback)

  useEffect(() => {
    let cancelled = false

    flags.getItem(name).then((item) => {
      if (!cancelled && item?.value !== undefined) setValue(item.value)
    })

    const handler = (item) => { if (!cancelled) setValue(item.value) }
    flags.on('setItem', name, handler)

    return () => {
      cancelled = true
      flags.off?.('setItem', name, handler)
    }
  }, [flags, name])

  return value
}

The case this actually solves

The kill switch.

A feature is causing errors. With load-time flags, turning it off means a deploy, or waiting for everyone to reload — and the people affected are the ones staying on the page.

With a live flag, the feature stops in every open client within a second. That is the difference between a five-minute incident and a forty-minute one.

This is the reason to do it. Not gradual rollouts, not A/B tests — the ability to stop something immediately.

The fallback matters more than the flag

Every flag read needs a sensible default for when the value is unavailable — first paint, network failure, service unreachable.

And the default should be the safe state, which is usually the old behaviour.

A flag defaulting to "new feature on" when the flag service is unreachable means an outage in your flag delivery turns the new feature on for everyone, which is precisely backwards.

Do not put secrets in flags

Client-readable means user-readable.

A flag saying enableAdminPanel: false does not protect the admin panel. Anyone can read the object and anyone can see the code branch.

Flags control what is shown. Authorisation controls what is permitted, and it lives on your server. These are not the same mechanism and treating them as one is a recurring cause of embarrassing disclosures.

Per-user flags

Two approaches.

A flag object per user — flags:user:{id} — read alongside the global one, with the user value winning. Simple, and it is one object per user.

Rules in the global object and evaluate client-side — { newCheckout: { enabled: true, percentage: 20 } }. Fewer objects, and the rule is visible to the client, which matters if the rule itself is sensitive.

For anything where the targeting must not be visible, evaluate on your server and deliver the resolved value.

Environments

Separate objects at minimum — flags:production, flags:staging.

Separate projects preferably, so a development key cannot write production flags. See object classes and ids.

This is the mistake that produces a memorable incident, and it is entirely preventable at setup.

Who can change them

Write access to the flag object is the ability to change production behaviour.

Which means: flags are written from your backend, through an interface with authentication and an audit log. Not from a client, and not by anyone with the project's API key.

And log every change — what, who, when. When something breaks at 3pm, the first question is what changed at 3pm.

When a flag service is the better answer

Being clear about the boundary.

Purpose-built flag services give you targeting rules, gradual rollout percentages, audit logs, approval workflows, scheduling, and integration with your experimentation stack.

This approach gives you a value that changes live, and you build the rest.

Use this when: you want a kill switch, you have a handful of flags, and you do not want another vendor.

Use a flag service when: flags are central to how you ship, you need targeting and experimentation, or compliance requires the audit trail.

And note that many flag services now offer streaming updates too, which removes the main advantage of doing it yourself.

The short version

The case is the kill switch — stopping a feature in open clients within a second, not after a deploy.

Every read needs a fallback, and the fallback is the old behaviour.

Flags are not authorisation. Client-readable is user-readable.

Separate projects per environment, so a development key cannot write production flags.

And a purpose-built flag service is better if flags are central to how you ship — this is for the handful of switches you want to be able to throw.