NNabeel Hassan

Blog · November 11, 2026 · 8 min read

Feature Flags on a Small Team: Kill Switches First, Experiments Later

By Nabeel Hassan — AI Engineer · ICPC World Finalist

TL;DR: A small team does not need a feature flag platform, an experimentation dashboard or a hundred toggles. It needs a handful of kill switches on the things that are expensive to undo: features inside an app that has to pass store review, integrations that write to a client's CRM or calendar, and any change to a live phone agent. Keep flags in one server-side place, give every flag a safe default for when that place is unreachable, scope flags by app version and platform, decide in writing who is allowed to flip each one, and delete release flags within a few weeks of a feature going fully live. A/B testing is a different job, and most early products do not have the traffic for it yet. I have run this setup as CTO at RAQTS across Unity, React Native and Next.js, and the same rule shapes how I ship voice agents for clients.

The question I ask about any change before it goes out is not "will this work?" It is "if this is wrong, how long until it stops hurting?" For a website on a modern host, the answer is minutes: redeploy the previous version. For a mobile app, it is the length of a store review plus however long people take to update, which for some users is never. For a voice agent answering a clinic's phones, it is every call that comes in while you are still figuring out what went wrong.

Feature flags are how you make that answer short everywhere, including the places where a rollback is slow. On a small team, that is the whole point of them.

What a feature flag actually is

A feature flag is a value the running software reads at runtime to decide which path to take, stored somewhere you can change without shipping new code. It can be a database row, a remote config key, or a field in a JSON document your backend serves. The mechanism matters less than the decision you have moved out of the build and into something you control live.

Flags get used for several different jobs, and mixing them up is how teams end up with a mess:

On a team of two to nine people, I build the first two from day one, treat the third as normal configuration, and push back on the fourth until the product has enough traffic to make the numbers mean something.

Where kill switches earn their keep

Not every feature needs a flag; each one adds a branch to test and clean up later. I put them where undoing a mistake is slow or the damage spreads to someone else's system.

Anything inside a store-reviewed app

At RAQTS the product spans a Unity app called Lumo, React Native mobile apps and a Next.js web portal, all reading from one backend, with releases going through App Store and Play Console review. The web portal can be fixed in minutes. A shipped mobile binary cannot. If a new screen crashes on a particular device, or a new flow confuses people, the fix is at least a review cycle away, and older versions linger on phones long after that.

So new features in the store builds sit behind a server-controlled flag that can be scoped by app version and platform. That turns "wait for review and hope" into "turn it off now, fix it calmly, ship the fix". It also means a feature can land in a build before it is switched on, so the review calendar stops dictating launch dates. I covered the wider version of this problem in supporting old mobile app versions; flags are one of the rules there, and the one I would refuse to skip.

Integrations that write to someone else's system

A bug that only affects your own screen is embarrassing. A bug that writes junk into a client's CRM, double books their calendar or texts their customers twice is a cleanup project with an apology attached. Every integration that writes outward gets its own off switch, separate from the feature that triggers it.

In the voice agent work I have done at Fortell AI and Tested Media, that means the booking step, the CRM update and the follow-up SMS can each be disabled independently of the agent itself. If the calendar integration starts failing, the agent should not go silent or start apologising on every call. With the booking switch off it falls back to taking the caller's details and promising a callback, which is a worse experience but a safe one. The same thinking runs through how I plan for voice agent outages and failover: decide in advance what degraded looks like, then make it one switch away.

Live phone agents

Changing a live agent's prompt or flow is a deploy, even when the platform makes it feel like editing a document. I keep the previous version of an agent available and route between versions, so rolling back is a routing change rather than a rewrite under pressure. Paired with regression testing for voice agents, that makes changes boring, which is exactly what a business owner wants from the thing answering their phone.

The rules I follow when building flags

One place, read on the server where possible

Flags scattered across environment variables, constants and two different services are flags nobody can find at 11pm. I keep them in one place the backend serves, and where I can, the server makes the decision rather than every client. If the server decides whether a feature is available, fixing a bad decision fixes it for every app version at once. It is the same reason RAQTS's backend owns leaderboard ordering instead of each client computing it.

Every flag has a safe default

The flag service will be unreachable at some point: no network on the device, a cold start before config has loaded, a bad deploy of the config itself. The code has to know what to do with no answer. My default is that new and risky features fail closed, so they stay off, and safety features fail open, so a fallback stays on. Write the default next to the flag definition, not in someone's head. A kill switch that defaults to "feature on" when config cannot load is not a kill switch.

Scope by version and platform

On mobile, a flag that is simply on or off for everyone is too blunt. The bug is often in one platform, or in one range of builds, and turning the feature off everywhere punishes the users who were fine. I want to be able to say "off for iOS builds below this version" without a code change. That needs the app to send its version and platform with every request, which is worth doing from version one anyway.

Decide who is allowed to flip it

A switch nobody is authorised to touch is decoration. For each kill switch I write down who can flip it and under what conditions. For client voice agents, that list includes someone at the business, with a short runbook and screenshots, because I will not always be the first person awake when something goes wrong. That handover is part of how I hand a voice agent over to a client.

Log every change

Every flag change gets recorded: what, who, when, and why. When a metric moves, the first question is "what changed?", and a flag flip is a change just as much as a deploy.

Flag debt is real debt

Release flags are supposed to be temporary. In practice they become permanent branches nobody dares delete, and each one doubles the paths through that code.

What keeps it under control:

This is the same lens I use for technical debt in general: a stale flag on code you change every week charges interest every week. In code review, "how do we turn this off, and when do we delete the flag?" is a question I ask on any change that ships to a store or a phone line.

When you actually need experiments

A/B testing gets the most attention and is what small products need least. An experiment only tells you something if each variant gets enough users to separate a real difference from noise. Early on, you rarely have that. You learn more from watching ten people use the product, or listening to twenty call recordings, than from splitting a few hundred sessions two ways. Once a product has real volume, the flags you already have become the delivery mechanism, and a dedicated platform may earn its cost.

The minimum setup I would build tomorrow

If I were starting a new product this week, this is all I would add on day one:

  1. A flags table or config document the backend serves, with a name, value, safe default, owner, removal date and description for each flag.
  2. The app sending its version and platform on every request, so flags can be scoped.
  3. A kill switch around each outward integration and each new feature in a store build.
  4. A change log, even if it starts as an append-only table.
  5. A one-page note saying who can flip which switch, and what the product does when each one is off.

That is a day or two of work, and it changes the answer to "how long until this stops hurting?" from days to seconds.


I work as a hands-on fractional CTO and engineer for startups in the US, UK and Europe, across web, mobile, Unity and XR, and production AI voice agents. If you are about to ship something you cannot easily take back and want a second pair of eyes on how to make it safe, read more about how I work as a fractional CTO, or book a call.

FAQ

Does a small startup need a feature flag platform?

Usually not at first. A flags table or config document served by your backend, with a safe default, owner and removal date for each flag, covers kill switches and release flags. A dedicated platform starts to earn its cost when you have enough traffic to run real experiments.

Which features should have a kill switch?

Anything that is slow or painful to undo: new features inside an app that has to pass App Store or Play review, integrations that write to someone else's system such as a CRM, calendar or SMS sender, and changes to a live phone agent. Code that can be redeployed in minutes needs one much less.

What should happen if the flag service is unreachable?

Each flag needs a written safe default. New or risky features should fail closed and stay off, while safety fallbacks should fail open and stay on. A kill switch that defaults to the feature being on when config cannot load does not protect you.

How do you stop feature flags turning into technical debt?

Give every release flag an owner and a removal date when it is created, and count removing the flag and the dead branch as part of finishing the feature. Label permanent kill switches clearly so they survive cleanups, and test both sides of any flag while it exists.

Building something in this space?

I take on AI-agent, automation and product work directly — scoped fast, shipped fast.

Book a discovery call →

Keep reading