OpenFeature — Stop Building Flag Systems in Year 3. Start on Day 1.
Most teams hardcode their packaging logic for 2-3 years, then spend a quarter refactoring when engineering hits 15 people. OpenFeature is the discipline that makes that refactor unnecessary — adopted on Day 1, it costs nothing. Adopted on Year 3, it's a tax.
May 14, 2026 • 13 min read • Alexandre Bergère

Weekly Stack #06 — OpenFeature
Every week, we break down one tool from the stack that powers Kaiten — what it does, why we picked it, and how it fits into a unified SaaS architecture.
This issue is special. OpenFeature isn't a tool. It's a standard. And it's the one discipline that, adopted on Day 1, makes a category of technical debt simply disappear.

Prefer the printable version? Download the PDF.
The Year 3 Refactor
Here's a story you've probably lived through, or watched a friend live through.
You're building a SaaS. Year 1: small team, fast iteration, you hardcode plan checks (if user.plan == 'pro') directly in your codebase because it's faster. Year 2: pricing evolves, plans multiply, you start scattering targeting logic across 47 files. Year 3: engineering team grows to 15 people, your CEO wants A/B testing, your PM wants progressive rollouts, your CFO wants entitlements that match the contract. You finally adopt a flag system — and you spend a quarter refactoring three years of hardcoded conditionals into flag evaluations.
This refactor is the most predictable, most preventable technical debt in B2B SaaS. Every team does it. Every team underestimates it. Every team regrets not starting earlier.
OpenFeature is the discipline that makes this refactor unnecessary. Not because it's a magic flag system, but because it's a standard that you can adopt on Day 1, with zero infrastructure, and never have to refactor away from.
What is OpenFeature?
OpenFeature is a CNCF-incubating open standard for feature flag evaluation. It's not a tool you install in production — it's a specification that defines how your application code talks to any flag management system, without coupling your code to a specific vendor.
Think of it like JDBC for databases, or OpenTelemetry for observability. Your code uses a standard API, and a "provider" plugs in behind the scenes to evaluate against your chosen backend.
import { OpenFeature } from '@openfeature/server-sdk';
import { OFREPProvider } from '@openfeature/ofrep-provider';
// One line to register a provider. Switch providers without
// changing any other line of code in your app.
OpenFeature.setProvider(new OFREPProvider({
baseUrl: 'https://flags.your-system.com'
}));
const client = OpenFeature.getClient();
// Standard evaluation API. Same call regardless of backend.
const isEnabled = await client.getBooleanValue(
'new-checkout-flow',
false, // default if anything fails
{ targetingKey: user.id } // evaluation context
);Your application code calls getBooleanValue (or getStringValue, getNumberValue, getObjectValue). The OpenFeature SDK routes that call through whatever provider you've registered. The provider can be anything: a local YAML file, an open-source server, a commercial flag service, or any OFREP-compatible system.
The point is: your application code doesn't change when you switch providers. That single property is what makes Day 1 adoption rational.
The Architecture: Client-Side vs Centralised
To understand why the swap is so cheap, you need to see where each piece lives.
There are four layers in the OpenFeature model, but they don't all live in the same place:
Client-side (inside your application, deployed with your code):
- Your Application — the code that calls
getBooleanValue - OpenFeature SDK — the standard interface, in-process
- Provider — an adapter that translates SDK calls into a specific protocol (file read, HTTP request, gRPC call). Also in-process.
Centralised (deployed separately):
- Flag Backend — the system that stores flags, evaluates targeting rules, and serves the data. This is the only piece that lives outside your app.
This separation is the key. When you "switch providers," you're not migrating infrastructure — you're swapping one in-process plugin (the Provider) for another. The application code never changes. The SDK never changes. Only the Provider line changes, and possibly the Flag Backend it points to.
Switching from a local YAML file to a remote SaaS like Kaiten is literally one import and one line of configuration. Switching from LaunchDarkly to Unleash is the same — provided you've adopted the standard.
That's why Day 1 adoption is rational. You're not committing to infrastructure on Day 1. You're committing to a code pattern that lets you choose infrastructure later, freely, at your own pace.
Why Day 1, Not Year 3
Most engineering arguments against early flag adoption boil down to YAGNI: "we don't need flags yet, we'll add them when we need them." That argument is wrong, and it's wrong for a specific reason.
Adopting OpenFeature on Day 1 has near-zero cost — and almost no infrastructure commitment. Because the Provider lives client-side, you can start with a local file provider that reads flags from a YAML in your repo. No service to run. No monthly bill. No external dependency. Your first "flag system" is literally a file.
Three years later, when you actually need progressive rollouts and targeting, you replace that file provider with one pointing to a real backend. Zero application code changes. You swap the provider registration — same pattern, different backend:
new FileProvider('./flags.yaml');
// becomes
new OFREPProvider({ baseUrl: 'https://app.kaiten.sh' });The SDK is the same. Your getBooleanValue calls are the same. Only the Provider line — that in-process adapter — changes.
Compare that to the Year 3 scenario where you haven't adopted the standard:
- 47 files with hardcoded plan checks
- 6 different code patterns for "feature gating"
- A quarter of engineering time refactoring everything to use a flag SDK
- The refactor itself introduces bugs (you've all been there)
- The team now has to learn LaunchDarkly's SDK, then realize a year later that they want to migrate to a cheaper provider, then realize they've coded against LaunchDarkly's specific APIs
The cost asymmetry is enormous. Day 1 adoption costs an afternoon. Year 3 adoption costs a quarter. And critically, Day 1 adoption preserves your optionality — you can migrate providers freely. Year 3 adoption usually locks you in, because the refactor is so painful that nobody wants to do it twice.
This isn't a hypothetical. This is the same pattern as TypeScript adoption, test coverage, structured logging, OpenTelemetry instrumentation. The teams that adopt these on Day 1 never regret it. The teams that adopt them on Year 3 pay a tax. OpenFeature belongs in that same category.
The Four OpenFeature Capabilities Most Teams Don't Know About
The basic getBooleanValue call is the table-stakes feature. Where OpenFeature gets genuinely interesting is in four capabilities that most introductory articles skip.
1. Hooks — extending evaluation without touching application code
Hooks let you intercept the flag evaluation lifecycle: before evaluation, after evaluation, on error, finally. You can use them to add structured logging, validate evaluation context, emit metrics, or enforce policies — all without touching the code that calls getBooleanValue.
class AuditLogHook implements Hook {
after(hookContext, evaluationDetails) {
log({
flag: hookContext.flagKey,
value: evaluationDetails.value,
reason: evaluationDetails.reason,
user: hookContext.context.targetingKey,
});
}
}
OpenFeature.addHooks(new AuditLogHook());Now every flag evaluation in your app produces an audit log entry. Implemented once, applied everywhere. You can compose multiple hooks (logging + metrics + validation) and they all run on every evaluation. This is the kind of cross-cutting capability that would cost weeks to build manually.
2. Multi-Provider — combining backends transparently
OpenFeature supports running multiple providers under a single client. This sounds esoteric until you realize how useful it is during migrations.
You're migrating from LaunchDarkly to a cheaper provider. With a traditional setup, you'd need to migrate every flag at once (impossible) or maintain two SDKs in parallel (painful). With OpenFeature multi-provider, you register both backends and define a strategy: try LaunchDarkly first, fall back to the new provider if the flag doesn't exist. Migrate flags one at a time. Zero risk.
const multi = new MultiProvider([
{ provider: new LegacyProvider() },
{ provider: new NewProvider() },
], strategy: 'FirstMatch');
OpenFeature.setProvider(multi);This pattern alone has saved teams from being stuck on overpriced flag vendors. You don't migrate code, you migrate flags — one at a time, on your schedule.
3. OpenFeature CLI — code generation for type-safe flags
This is the newest and least-known capability in the OpenFeature ecosystem. The OpenFeature CLI introduces a manifest-driven workflow: declare your flags in a JSON file, run a code generation command, and get strongly typed accessors in your language of choice.
Start with a flags.json manifest:
{
"$schema": "https://raw.githubusercontent.com/open-feature/cli/refs/heads/main/schema/v0/flag-manifest.json",
"flags": {
"newUserOnboarding": {
"description": "Shows the new streamlined onboarding flow",
"flagType": "boolean",
"defaultValue": false
},
"maxLoginAttempts": {
"description": "Maximum number of login attempts before lockout",
"flagType": "integer",
"defaultValue": 3
}
}
}Then run:
openfeature generate nodejsAnd the CLI generates a fully typed client. Instead of writing:
// String literal. No type checking. Easy to typo.
const isEnabled = await client.getBooleanValue(
'newUserOnboarding', false, context
);You write:
// Strongly typed method. Autocomplete. Compile-time safety.
const isEnabled = await flags.newUserOnboarding(context);This unlocks three properties that compound over time. Single source of truth: the flag manifest is the contract — no more inconsistent flag keys scattered across the codebase. Type safety: typos and wrong default types are caught at compile time, not in production. Documentation in code: each flag's description, type, and default value become inline JSDoc, visible in your IDE during development.
Generators are available for C#, Go, Java, Node.js, NestJS, Python, and React (all currently in alpha). The CLI itself is still experimental — but the pattern it establishes (manifest-driven flag definitions) is one of the strongest arguments for Day 1 adoption. You're not just writing flag evaluations; you're declaring a typed contract that your team can rely on as the codebase grows.
4. OFREP — the protocol that breaks vendor lock-in for good
OFREP (OpenFeature Remote Evaluation Protocol) is the underrated star of the OpenFeature ecosystem. It's a standard REST API for flag evaluation: the OpenFeature community defines the exact HTTP contract that a flag management system should implement.
Why this matters: any system that implements OFREP can be evaluated by any OpenFeature SDK using the generic OFREP provider. You don't need a vendor-specific SDK. You don't need a vendor-specific provider. The SDK calls a standard URL, the system responds in a standard format, evaluation works.
import { OFREPProvider } from '@openfeature/ofrep-provider';
OpenFeature.setProvider(new OFREPProvider({
baseUrl: 'https://flags.your-system.com',
headers: { Authorization: `Bearer ${apiKey}` },
}));That's it. The SDK now evaluates flags against any OFREP-compatible system. Kaiten is OFREP-compatible by default. So are flagd, GO Feature Flag, Unleash, and a growing list of others. You're not locked to anyone.
This is the deepest argument for OpenFeature: the standard isn't just an API in your code. It's a protocol that the entire ecosystem can implement. The more systems implement OFREP, the more your code remains portable forever.
Flags Are Not Entitlements (And OpenFeature Doesn't Pretend Otherwise)
Here's the nuance most flag articles miss: even with OpenFeature, a feature flag is not an entitlement.
A flag answers "is this feature active right now?" — it's a delivery mechanism. An entitlement answers "does this customer have the right to use this feature?" — it's a rights mechanism.
OpenFeature gives you a clean way to evaluate flags. It doesn't, by itself, answer the question of whether the customer is actually allowed to see the feature based on their plan, contract, or usage. That's a different layer — and conflating the two creates real technical debt.
I've written about this in depth in a separate piece: Entitlements vs Feature Flags: Stop Using Flags as Business Logic. If you're adopting OpenFeature, that article is the natural companion read. The TL;DR: use OpenFeature for delivery, use a proper entitlement system for rights, and make sure they're linked so a flag can never accidentally grant access to a feature a customer hasn't paid for.
This is exactly the model Kaiten implements: OpenFeature-compatible flag evaluation, with each flag constrained by the customer's entitlements. The flag doesn't lie. The entitlement isn't invisible. Both layers are unified.
How Kaiten Fits in the OpenFeature Ecosystem
Three things to know if you're considering Kaiten as your flag backend:
Kaiten is OFREP-compatible — it implements the OpenFeature Remote Evaluation Protocol natively. You don't need a Kaiten-specific SDK or a Kaiten-specific Provider. You use the standard OpenFeature SDK with the generic OFREPProvider, point it at your Kaiten endpoint, and you're done. Your code is portable to any other OFREP-compatible backend, with no rewrites.
Kaiten flags are entitlement-constrained. When you evaluate a flag through Kaiten, the system automatically considers the customer's entitlements. A Pro-only feature flag won't return true for a Free user, regardless of targeting rules. This is the unified model — flags and entitlements in one data model, instead of two systems that have to be manually kept in sync.
Kaiten is open-source. No vendor lock-in at any layer: not at the SDK (OpenFeature standard), not at the protocol (OFREP standard), not at the backend (Kaiten is open-source). You can self-host. You can fork. You can switch.
That's the layered openness that matters: standard SDK, standard protocol, open-source backend. The opposite of the LaunchDarkly model — where the SDK is proprietary and migrating off means rewriting your application code.
Market Landscape
OpenFeature itself isn't a competitor to anything — it's a standard. The real comparison is between adoption approaches: do you adopt the standard, or do you couple your code to a proprietary SDK?
OpenFeature + open backend (flagd / GO Feature Flag / Unleash / Kaiten) — Standard SDK, swappable backends, no lock-in. The right architectural choice for any team building for the long term.
LaunchDarkly — Mature, polished, expensive. The de facto enterprise default. Their SDK is proprietary; migrating off LaunchDarkly later means refactoring application code. They've added some OpenFeature support, but the experience is still built around their SDK first.
Flagsmith — Open-source flag management with hosted and self-hosted options. Has an OpenFeature provider, but their SDK is often the default in tutorials. Good middle ground if you want open-source without committing to OpenFeature.
Unleash — Open-source, strong on operational flags, supports OpenFeature. Less focus on product-side concerns (entitlements, billing alignment). Right choice if your needs are ops-heavy.
DIY (config files + hardcoded checks) — Works at 5 users. Breaks at 500. This is the Year 3 refactor waiting to happen.
The Bottom Line
OpenFeature isn't an optimization. It's a discipline.
The teams that adopt it on Day 1 don't suddenly become better at feature management — they just avoid the predictable refactor that consumes a quarter of engineering time three years in.
The same way you don't wait until Year 3 to start using TypeScript, or to add tests, or to instrument observability. You install it Day 1 because the marginal cost is near zero and the long-term return is enormous.
Same logic. Same answer. OpenFeature in your next commit, before you even need flags. Future-you will say thank you.
This is Weekly Stack #06. Every week, we break down one tool from the Kaiten stack. Previously: Firecrawl — stop treating it like a scraper, it's a web observability platform.
Related deep dive: Entitlements vs Feature Flags: Stop Using Flags as Business Logic — the companion article for anyone serious about flag architecture.
Kaiten works with the OpenFeature standard, out of the box
OFREP-compatible flag evaluation through any OpenFeature SDK. Flags constrained by entitlements. The unified model, on the open standard.
You might also like

Firecrawl — Stop Treating It Like a Scraper. It's a Web Observability Platform.
Most teams use Firecrawl for one thing: feeding their RAG pipeline. They miss the three features that turn it into something fundamentally different — a continuous observability layer for the public web.
May 7, 2026 • 10 min read

Neon — Postgres Rebuilt for the Cloud (And Why Our Free Tier Burns Out)
Why we use Neon for staging and production at Kaiten — and the brutal honesty about why our free tier burns out before the end of the month thanks to Debezium.
April 30, 2026 • 7 min read

Dub.co & Ngrok — The Two Utilities That Make Your Work Visible
A special double-edition Weekly Stack covering two small tools that punch way above their weight: Dub.co for tracking every link you share, and Ngrok for exposing your local server to the world.
April 23, 2026 • 9 min read