Context

Feature Flag Runner came from a practical need around rolling out changes behind feature flags. A feature flag as a simple boolean switch is useful, but for riskier changes it is often not enough.

When we introduce new code, we do not only want to know whether the flag is on or off. We also need to see whether the new path actually ran, how often it ran, in what context, how long it took, how many errors it produced, what result it returned if it returned one, and in some cases whether its output differs from the original behavior.

Problem

Without a shared pattern, it was easy to end up with only a boolean condition around a feature flag. Everything else became extra work that could easily be forgotten during implementation or postponed until later.

But “later” often meant the moment when the change was already running and a concrete problem had to be investigated. Observability was then not a natural part of the rollout, but a follow-up fix for something that should have been visible from the beginning.

Approach

I created a runner that wrapped the old and new behavior into one shared pattern. Instead of each piece of code handling feature flags, logging, and measurement in its own way, the runner received the original path, the new path, and configuration for what should run, be logged, be measured, or be compared.

That made it possible to use different modes depending on the risk of the change. Sometimes it was enough to switch to the new behavior. In other cases, it made sense to run the new path in the background alongside the original one, measure its performance, monitor errors, or compare results without immediately changing behavior for users.

The feature flag moved from a simple condition to a place where safer rollout and basic observability were prepared from the start.

Outcome

The value of the runner was that it unified how changes behind feature flags were executed and measured. The safer path became the simpler path.