Every homegrown feature flag system starts the same way: a boolean column, an if statement, and a deploy. It takes an afternoon, it works, and for a while it’s the cheapest thing in the codebase. The build-vs-buy question almost never turns on whether your team can build a flag system. Of course you can. It turns on whether a flag platform is the thing you want to be maintaining in two years, and what it actually costs once that afternoon’s if statement has to grow up.
That growing-up is where the estimate goes wrong. The first feature behind a flag is trivial. The second team that wants targeting, the first 2 a.m. kill switch, the audit log a customer’s security review asks for, the SDK for the language the mobile team uses, and the 200 stale flags nobody remembers: those are the system. This post lays out a cost-honest framework for the decision, including the cases where building your own genuinely is the right call, and how to move off a homegrown system if you already built one.
Key Takeaways
- The day-one cost of a homegrown flag is near zero. The multi-year cost is targeting, percentage rollouts, an audit log, multi-language SDKs, a propagation layer, observability, and cleanup tooling that someone has to own.
- The decision is rarely about capability. It’s about total cost of ownership and opportunity cost: is reinventing a flag platform the best use of your engineers?
- There are real reasons to build: flags are your product, you need air-gapped isolation no vendor can satisfy, or you only need a static toggle that’s the same for every user (that last one is configuration, not a flag platform).
- Software maintenance runs 40–80% of a system’s total lifecycle cost (Robert Glass, Facts and Fallacies of Software Engineering). A flag platform you build is mostly maintenance you’ve signed up to own indefinitely.
- Already built one? Move off it one flag at a time behind a single read function, and delete the dead flags first, because a deleted flag never has to be migrated.
”Build” doesn’t mean the if-statement. It means the platform.
A feature flag is a runtime branch. A feature flag platform is everything that makes that branch safe to operate at scale, and the gap between the two is where build estimates quietly fail. Martin Fowler and Pete Hodgson make the distinction precise: the toggle point is the one line that reads the decision; the toggle router is the configuration, targeting, and evaluation logic behind it (martinfowler.com). Building the toggle point is the afternoon. Building the router is the project.
Here’s the accretion. You ship the first flag as a config boolean. Then a second team wants it on for staging but off in production, so you add per-environment values. Then product wants it for one beta customer, so you add per-user targeting. Then someone wants a 5% rollout, so you add deterministic bucketing. Then a customer’s auditor asks who turned a flag on, so you add an audit log and roles. Then the feature misbehaves and you need it off in seconds, not a redeploy, so you add a streaming propagation layer. Then the mobile team needs it in Swift and the data team needs it in Python, so now you maintain SDKs. None of these is hard in isolation. Together they’re a product.
The point isn’t that any one capability is unattainable. It’s that the build estimate is almost always scoped to the green bar, and the blue bars arrive as a stream of “can we also” requests over the following year. By the time you’ve answered all of them, you’ve written a flag vendor’s product as a side quest.
The cost that doesn’t show up in the build estimate
The build estimate prices the build. It rarely prices the operation, and operation is where a flag platform actually spends your money. Software-engineering research has held for decades that maintenance, not initial construction, dominates a system’s cost: Robert Glass put it at 40 to 80 percent of total lifecycle spend (Facts and Fallacies of Software Engineering). For a flag platform, that slope is maintenance, on-call, SDK upkeep across languages, security review of the evaluation path, and the engineering attention pulled away from the product your customers pay for. The figures get concrete when a vendor publishes them: Unleash, an open-source flag company, says it has put more than 22 person-years into building its platform, and reports one customer, Wayfair, was spending over $3 million a year operating a homegrown system before replacing it (Unleash, 2024). Those are vendor numbers, so weight them accordingly. The order of magnitude is the point: this is not a two-sprint project.
Two costs hide inside that slope. The first is debt. Flags rot whether you build or buy, and most are never removed. Pete Hodgson’s canonical treatment frames toggles as “inventory which comes with a carrying cost,” something teams have to actively work to keep low (martinfowler.com). A bought platform at least ships staleness detection and a removal workflow to manage that inventory. A homegrown one inherits the same carrying cost with a blank page where the tooling should be, so building the cleanup machinery also lands on your team. The second hidden cost is reliability. DORA’s research links trunk-based development and loosely-coupled architecture to elite delivery performance (DORA), and feature flags are how teams practice trunk-based development without long-lived branches. That payoff only lands if the flag layer is dependable: the fail-open evaluation, the last-known-good caching, the sub-second propagation. That reliability engineering is the hard part, and it’s the first thing a quick internal build skips.
Read the shape, not the axis. A subscription is a line you can predict; a homegrown platform is a slope that keeps climbing because every new language, every security review, and every stale-flag pileup adds to it. The honest version of the build estimate isn’t “two sprints to ship v1.” It’s “two sprints to ship v1, then a standing claim on a fraction of an engineer forever.” If flags are not the thing your company sells, that standing claim is the real price.
When building your own is the right call
Buying isn’t automatically correct, and pretending otherwise would make this a sales pitch instead of a framework. There are three situations where building genuinely wins, and a fourth that looks like building but isn’t.
Build when feature management is your product. If you’re a platform company whose customers buy flag delivery, or you have flag requirements so specific that no vendor models them, then a flag system isn’t undifferentiated heavy lifting. It’s the differentiator. Build it, staff it, and treat it like the product it is.
Build when isolation rules out any vendor. Air-gapped environments, classified networks, and certain regulated workloads can’t send evaluation context to a third party, even a self-hosted one with the right certifications. If a hard compliance boundary forbids the data leaving your perimeter and a vendor’s self-hosted option doesn’t satisfy your auditors, the build path may be the only path. Just price the whole platform from the chart above, not the afternoon.
Build when you have a platform team to own it. The maintenance slope only works if someone’s job is to absorb it. A company with a dedicated developer-experience or platform-engineering team that already owns internal tooling can amortize a flag system across that mandate. A six-person product team without a platform function cannot, and shouldn’t pretend the slope will be free.
The fourth case isn’t really “build” at all. If you only need a static on/off that is identical for every user and never needs targeting, percentage rollout, or runtime change, you don’t need a flag platform. You need a config value in an environment variable. That’s not building a flag system; it’s correctly recognizing you don’t have a flag problem. The mistake is dressing a ENABLE_X=true env var up as a “feature flag system” and then discovering, the first time you want a 10% rollout, that you built the wrong thing.
When buying is the right call (the common case)
For most teams, flags are infrastructure, not product, and the right move is to buy. The argument is opportunity cost: the same engineers who would build and babysit a flag platform could be shipping the features your customers actually pay for. Engineering leaders already report losing 5 to 15 hours per developer each week to undifferentiated work (Cortex, 2024), and a homegrown flag platform is a standing addition to that pile rather than a one-time line item. Buying hands you the full capability set on day one. The targeting, the rollout discipline, the audit log, the observability, and the cleanup tooling all arrive built, instead of being assembled incident by incident over a year.
Buying also front-loads the practices that homegrown systems learn the hard way. A bought platform comes with progressive rollout, both-state safety, and a kill switch already designed, which means you adopt feature flag best practices by default rather than rediscovering each one after it bites you. The cautionary tale here is Knight Capital, whose in-house toggle reused a deprecated flag bit and triggered a $460 million loss in 45 minutes (Henrico Dolfing, 2019). That failure mode, and the other eight in our anti-patterns post, is exactly the kind of thing a hardened platform is built to prevent and a quick internal build tends to reproduce.
The standard objections to buying are real, so address them directly rather than waving them off:
| Objection to buying | The honest answer |
|---|---|
| ”It’s too expensive” | Per-seat vendors do get expensive. Flat-priced tools don’t, and the comparison is against the fully loaded build cost, not zero. |
| ”We’d have to self-host” | Some vendors force self-hosting; many don’t, and moving off a self-hosted flag tool is a common reason teams switch. Cloud-first tools remove the ops burden entirely, and the hosted-versus-self-hosted trade-off has its own breakdown. |
| ”Remote evaluation is slow” | Local-evaluation SDKs evaluate in-process from a cached, streamed config, so per-request cost is sub-millisecond. |
| ”Vendor lock-in” | The OpenFeature standard makes the SDK layer portable, so switching cost is a config change, not a rewrite. |
That last row matters more than it looks. OpenFeature standardizes the evaluation API across vendors, so “what if we want to leave” stops being a rewrite and becomes a provider swap. The Node.js, .NET, Python, Go, Java, PHP and Ruby provider setup shows what that swap looks like in code, including the parts the standard doesn’t carry across. Lock-in is a weaker argument against buying than it used to be.
How to actually run the decision
The decision comes down to four questions, asked in order, and the first “yes” gives you the answer. Is feature management your product? Do you only need a static toggle that’s the same for everyone? Do you have both a hard isolation requirement and a platform team to own the build? If none of those fire, buy.
Notice what the tree doesn’t ask: “can your team build it?” That question is a trap, because the answer is almost always yes, and it’s the wrong question. Capability was never the constraint. Ownership cost was.
Moving off a flag system you already built
The tree is for teams still deciding. Many reading this made the call years ago and are now paying every cost the estimate left out. A second team asks for per-user targeting and hears it’s on the backlog. Turning something off at 2 a.m. means a redeploy, because the flag values ship inside the build. When a customer’s security review asks who changed a flag last Tuesday, the only record anyone can find is a commit to a YAML file. The mobile team wants Swift. And nobody can say which rows in the flags table still gate anything.
Sound familiar? Then the slope in the chart above is already on your bill. If fear of the move is what’s keeping you there, that fear is reasonable, because swapping every flag at once over a weekend is a bet few engineering leads would sign off on. Martin Fowler calls the safer route a strangler fig. You grow the replacement around the old system one piece at a time until nothing reads from it, then turn the old one off.
Delete the dead flags before you move anything
Start with a list. Export every key the old system stores, then search the codebase for each one, and you’ll usually find a long tail of flags that have served the same value to everyone for months. Those are finished. Take the check out of the code and drop the row, and that flag is off the migration list for good. Kill switches and plan gates are built to last, so they’re the ones worth moving. The cleanup playbook has the triage buckets and the two-PR removal that keeps this safe, and both apply to a homegrown store unchanged.
Put one function in front of every read
If every call site already goes through one helper, something like isEnabled('checkout-v2', user), the migration happens inside it. If there’s no such helper, adding one is the first real change, because it gives you a single spot to decide where each flag’s value comes from. Moved keys go to Featureflip. The old store answers for the rest until their turn comes:
const MOVED = new Set(['checkout-v2', 'search-rerank'])
export function isEnabled(key: string, user: User): boolean { const legacy = legacyFlags.get(key) ?? false if (!MOVED.has(key)) return legacy return client.boolVariation(key, { user_id: user.id }, legacy)}The old value doubles as the SDK default. A key Featureflip can’t answer for serves exactly what it served yesterday. Create every new flag in Featureflip from the day the helper ships, so the old store stops growing while you drain it.
Move live flags one at a time
Recreate each surviving flag in Featureflip with the state it has today in every environment, and add its key to MOVED. Then give it a day. Copying a few hundred flags by hand is how the two sides drift apart, which is why the import belongs in a script against the Management API. Once a key has moved, its old row is only a fallback, and every real change to that flag happens in Featureflip. When the last one is across, replace the old-store lookup with a fixed default and delete the store.
Leave half-finished rollouts for last
Featureflip buckets users by hashing each ID with a salt it generates for the flag at creation, and your system hashed with something else entirely. The two assignments don’t line up. Move a flag sitting at 30% and roughly seven in ten of the users inside it land outside Featureflip’s 30%, while about as many new users land in. So wait until a partial rollout reaches 0% or 100%, where there’s nobody to reshuffle. If one can’t wait, move it anyway and expect the same share of users to keep seeing it, though mostly different people than before.
Let the cleanup finish itself
On a homegrown system, removing a finished flag waits until someone has a spare afternoon. Once the flag lives on Featureflip, its evaluation traffic marks it dead, and the flag cleanup Action in your CI opens a pull request that deletes the code path it gated, one flag per PR. You can keep the helper. List it in the Action’s accessors input and calls through it get matched like direct SDK reads, as long as the key is a string literal in the first argument. Turn on the archive sweep as well and the flag is archived once the merged removal has shipped, so the dashboard stops listing a flag the code no longer reads. A key built from a variable is one of the shapes it declines, and a declined flag is reported by name.
What “buy” looks like without the usual objections
Featureflip exists to make the “buy” path the obvious one by removing the objections in the table above. Each plan is one flat monthly price with nothing metered: no charge for active users, service connections, evaluation volume, or overage. Your traffic can triple and the invoice stays put. There’s no proxy or cluster to self-host, so you adopt it without taking on ops. Server-side SDKs evaluate in-process against a cached copy of your flags, and a check on the request path never waits on a network call, which keeps per-request cost sub-millisecond. Counting browser and mobile, there are 13 official SDKs. And the capabilities that a homegrown build accretes over a year, per-user targeting, percentage rollouts, an audit log on every change, per-evaluation events, and a one-click kill switch, are there from the first flag you create.
A framework like this is no use if it flatters the vendor who wrote it. If your situation is one of the genuine build cases above, a vendor is the wrong tool and we’d rather you know that. For a team whose product isn’t feature flags, a focused platform with nothing metered beats financing the slope on that build line. If you’re weighing specific vendors, the compare pages lay out where Featureflip fits against LaunchDarkly, ConfigCat, Flagsmith, Unleash, GrowthBook, and PostHog: whether a focused flag tool beats bolting flags onto PostHog’s analytics suite, how flat pricing holds up against GrowthBook’s per-user seats, and what you take on running Unleash’s open-source edition yourself. If LaunchDarkly is the incumbent you’re weighing against, the head-to-head on pricing and feature coverage has the full breakdown. Teams that have already decided to leave get a dedicated guide for teams leaving LaunchDarkly, and the pricing page has the flat numbers in full.
The shorter version
Build-vs-buy for feature flags is almost never a question of capability, because any competent team can write an if statement over a config value. It’s a question of total cost of ownership. The first flag is an afternoon. The platform it has to become (targeting, percentage rollouts, an audit log, SDKs for every language, a streaming propagation layer, observability, and cleanup tooling) is a standing claim on your engineers that the build estimate never priced. Build when feature management is your product, when a hard isolation rule plus a platform team make it viable, or recognize that a static toggle identical for every user is just an environment variable. For everyone else, the engineers who’d maintain a homegrown flag platform are better spent on the product your customers buy, and a vendor with nothing metered hands you the whole capability set, plus the best practices, on day one. If you already built one, delete its dead flags first, then move the rest across one at a time behind a single helper, holding half-finished rollouts until they reach 0% or 100%.
Frequently asked questions
Should we build or buy a feature flag system?
Buy, unless one of three things is true: feature management is your actual product, a hard isolation rule forbids any vendor and you have a platform team to own the build, or you only need a static toggle identical for every user (which is an environment variable, not a flag platform). For most teams flags are infrastructure, not product, so building reinvents undifferentiated work.
How much does it cost to build an in-house feature flag system?
Far more than the initial build estimate, because the estimate prices the first if-statement and skips the platform around it. Maintenance, not construction, dominates software cost over time: Robert Glass put it at 40 to 80 percent of total lifecycle spend. Add on-call, SDK upkeep across languages, and security review of the evaluation path. For scale, Unleash reports investing more than 22 person-years building its own flag platform (Unleash, 2024).
When does building your own feature flags make sense?
When feature management is your product or core differentiator, when an air-gapped or regulated environment rules out any vendor and you have a dedicated platform team to absorb the maintenance, or in the narrow case where you only need a static on/off and recognize it as configuration. Outside those cases, the opportunity cost of building usually outweighs the subscription you’d avoid.
Isn’t a feature flag just an if-statement?
The toggle point is. The platform behind it isn’t. Martin Fowler and Pete Hodgson distinguish the toggle point (the one line that reads the decision) from the toggle router (targeting, configuration, evaluation) that decides (martinfowler.com). Per-user targeting, percentage rollouts, an audit log, multi-language SDKs, and second-by-second propagation are the router, and that’s the part you’d be building.
Does buying a feature flag tool create vendor lock-in?
Less than it used to. The OpenFeature standard defines a vendor-neutral evaluation API, so the SDK layer is portable and switching providers is a configuration change rather than a rewrite. Pick a vendor that supports the standard and “what if we want to leave” stops being a serious objection to buying.
How do you migrate off a homegrown feature flag system?
One flag at a time. Delete the flags that have finished their job before anything else, because there’s no reason to carry them over. Then route every read through a single helper that sends migrated keys to the new platform and the rest to the old store, passing the old value as the SDK default. Leave partial rollouts for last and move them at 0% or 100%, since the new platform buckets users with its own hash.
Once you’ve decided to buy, the practices that keep flags from becoming next quarter’s incident are the same whether the platform is yours or a vendor’s. The feature flag best practices pillar covers the eight rules production teams converge on, and the feature flags vs environment variables guide draws the line for the static-toggle case above. One cost a homegrown system rarely budgets for is the flags nobody owns, which is why removing dead flags without anyone scheduling the work is worth understanding before you commit either way.
Featureflip is the platform this framework points toward: sub-millisecond local evaluation on the server, 13 SDKs, an audit log on every change, a kill switch built in, and dead flags removed by pull request, on a monthly plan with nothing metered. If you’re moving off a system you built, start with the Free plan and bring one flag across first. It’s free forever for one project.