Fix patterns
Rollout as a config change: feature flags across OpCos
A phased rollout across operating companies does not need to be a program. Ship the capability to production dark everywhere, validate it in one market against real data, then enable it per OpCo by flipping a flag. Rollback is the same flip in reverse, not a hotfix weekend. Done this way, rolling out to a new market stops being a project with a plan and a go-live date, and becomes a configuration decision someone makes on a Tuesday.
Why does a phased rollout become a program?
Look at the traditional shape. Each market gets its own project plan, its own UAT cycle, its own go-live weekend. Because every launch is a separate event with its own date, scope gets cut per market to hit that date, and the codebase quietly grows a branch per OpCo to hold the differences. The rollout is not slow because the software is hard. It is slow because the delivery shape is a set of parallel projects, each with its own queue, its own sign-off chain and its own regression run.
This is Conway's law showing up as an integration bill: a delivery structure organised market-by-market produces software organised market-by-market, and every fork you create you then pay to keep in sync forever. Coordination cost scales with markets times teams, which is why the tenth OpCo is harder than the first rather than easier. Nobody planned a per-market fork. It accreted, one reasonable exception at a time.
What does shipping dark actually change?
In the flag pattern the capability ships to production everywhere the day it merges, defaulting off. There are no market branches. The only per-market artefact is a row of configuration answering one question: is this flag on for this OpCo? Deploy becomes continuous and boring; release becomes a decision. That separation is the whole point, and it is not exotic - it is trunk-based development plus progressive delivery, the practices DORA associates with its highest-performing teams.
DORA's guidance on the branching half is blunt: keep three or fewer active branches, lasting no more than a few hours, merged to trunk at least once a day. Its continuous-delivery capability frames the goal as releasing changes of all kinds on demand - quickly, safely and sustainably - which is precisely what a per-OpCo flag buys you: the change is already deployed, so releasing it to a market is a switch, not a build.
The teams that work this way sit in a measurably different band. In the 2019 research, elite performers deployed 208 times more often and 106 times faster than low performers; in the 2024 data, roughly 19% of respondents reached the elite band at all. The lesson for a multi-market rollout is not the multiplier. It is the mechanism underneath it: when deploy is continuous and release is a flag, a small number of teams can serve many markets without spawning a project per market.
How do you turn a rollout into a config change?
Seven moves take you from a program to a decision. None of them require Amazon's headcount; they require refusing the per-market fork.
- Ship dark by default. Merge behind a flag that defaults off and keep deploying to production continuously. The capability is live in code everywhere before a single market sees it, so enabling a market moves no code.
- Make OpCo a first-class dimension of the flag. The key is (capability, market), not a global boolean. Turning a feature on in one OpCo should tell you nothing about the state of any other.
- Validate in one lead market on real data. Pick the OpCo with the appetite and the volume, enable it for a slice of traffic, and watch the numbers before widening. Local validation replaces the per-market UAT cycle.
- Keep one trunk; refuse the fork. When a market needs "just a small change", push it into configuration, not a branch. A per-market branch is a rollout program in disguise, and it is the exact thing the branch-count guidance warns against.
- Make rollback a flag flip. If enabling a market goes wrong, disabling it is the same operation reversed - seconds, not a redeploy and a cutover window. Cheap reversal is what makes the whole approach safe to try.
- Record every flip in the event stream. Who enabled which capability, for which OpCo, when - captured as an event, not a ticket comment. That gives you an audit trail your auditors will actually like, with no separate change log to reconcile.
- Measure per OpCo before you widen. Adoption and the cost-to-serve read per market tell you whether to roll forward to the next OpCo or hold. Widening stays a decision informed by numbers, never an inevitability on a plan.
Where does the pattern stop helping?
Flags are neither free nor universal, and pretending otherwise is how teams get burned. A boolean matrix spanning dozens of capabilities and a dozen OpCos is its own form of debt: stale flags nobody dares delete become permanent forks with better manners, and the test matrix grows with every combination you leave live. Budget for deleting flags once a market is fully on, or the config file becomes the fork you were trying to avoid.
Some changes also cannot ship dark. An irreversible data migration, a financial posting that lands in the SAP core, or a returnables balance that must not be double-counted while a flag is half-on - none of these becomes reversible just because a boolean guards it. The pattern that holds here is narrower: let the flag guard the read path while the write path migrates carefully behind it. Flags make reversible changes cheap. They do not make irreversible changes reversible, and the day you forget that distinction is the day a half-enabled flag corrupts a balance.
The real shift is not technical, it is who gets to decide. Once rollout is a configuration change, the person enabling a market is a product owner reading adoption numbers, not a programme manager defending a Gantt chart. The platform's job narrows to making that decision safe to get wrong: per-OpCo isolation, instant rollback and a clean audit trail, all falling out of one event bus rather than a fork per market. Brewers that get there stop scheduling launches by financial year and start making them the week a market is ready - which, across twenty-odd OpCos, is the difference between a roadmap that ships and a backlog that never clears.
Frequently asked questions
Isn't shipping code to production before a market is live risky?
No riskier than leaving it in a branch, and far easier to reverse. Dark code defaults off and touches nothing until you enable it per OpCo. Because deploy is decoupled from release, you validate in one market and roll back with a flag flip, not a redeploy or a cutover weekend.
How is this different from maintaining a separate build per market?
A per-market build is a fork: every market carries its own branch, its own regression run and its own drift. The flag pattern keeps one trunk and pushes the market difference into configuration. DORA associates three or fewer active branches with elite delivery; a build per OpCo guarantees the opposite.
What kinds of change can't just ship behind a flag?
Irreversible ones. A data migration, a financial posting to the SAP core, or a returnables balance can't be double-counted while a flag is half-on. Guard the read path with a flag while the write path migrates carefully. Flags make reversible changes cheap; they don't make irreversible changes reversible.
Stuck with exactly this?
BrewOS builds the full route-to-market stack for global brewers — order capture, stock, loyalty, returnables, delivery and analytics on one event bus, run by a team of ~20 engineers. Bring us the feature that’s been stuck the longest and we’ll show you how we’d ship it in days.
Book a 30-minute walkthrough