Blog
Explainer

Entitlements are not feature flags, even when the same component renders both

A flag says the code is ready. An entitlement says this customer paid. Same boolean at the render site, different owner, lifecycle and failure mode.

Dharmendra Jagodana6 min read

In short

A feature flag says whether code is ready to show. An entitlement says whether this customer paid for it. At the render site both are a boolean around a component, but they have different owners, change on different schedules and fail in opposite directions. Flags die after a rollout. Entitlements outlive it.

A feature flag says whether code is ready to show. An entitlement says whether this customer paid for it. At the render site they look identical, a boolean around a component, and that is the whole reason they get confused.

The confusion is cheap until the first pricing change. Then someone spends an afternoon in a flag dashboard trying to remember which of forty toggles mean "Pro" and which mean "we were testing that in March".

Why the two look the same

Because the UI cannot tell them apart. Here is a dashboard with both kinds of gate on it:

<WhenWorkspaceFeatureEnabled slug="advanced-analytics">
  <AdvancedAnalytics />
</WhenWorkspaceFeatureEnabled>

<WhenUserFeatureEnabled slug="beta-editor">
  <NewEditor />
</WhenUserFeatureEnabled>

The first one is an entitlement. advanced-analytics is on because the workspace is on a plan that includes it, and it goes off on their next page load or session refresh after the downgrade. The second one is a flag. beta-editor is on because someone put this user on a targeting list, and it goes off when the editor ships to everyone and the flag is deleted.

Same shape. Same slug prop. And we ship both under a module called feature flags, with docs that call them both feature flags, which is a fair description of the mechanism and a bad description of what they are for. This post exists partly to correct our own naming.

What actually differs

Who owns it. A flag is owned by the engineer who is shipping the thing. An entitlement is owned by whoever owns the pricing page. When those are the same person, which they are at every company with under ten people, the difference feels academic. It stops being academic the first time a salesperson promises a feature to a customer and expects it to turn on without a deploy.

Where the truth lives. A flag's truth is a list: these users, this percentage, this environment. An entitlement's truth is the plan. The plan version says which features, limits and quotas it includes, and the entitlement is read from that, not stored beside it. Change the plan, and every workspace on it changes with it. That is not a nice-to-have. It is the definition.

How it dies. A flag's endpoint is deletion: the rollout finishes, the flag is 100% on, someone removes the if. A flag that survives past its rollout is technical debt with a dashboard entry. An entitlement never dies while the plan exists. Deleting one is a pricing decision, not a cleanup.

Which way it fails. A flag stuck on shows unfinished code to everyone. A flag stuck off hides a finished feature. Annoying, both recoverable, and neither costs money directly. An entitlement stuck on gives a feature away to customers who did not pay for it, and you will not find out, because nobody emails to say they are getting too much. An entitlement stuck off refuses a paying customer, and you will find out within the hour.

Feature flagEntitlement
AnswersIs this ready?Did they pay for this?
Owned byEngineeringPricing
Truth lives inA targeting listThe plan version
Changes whenA rollout movesA plan changes, or a customer switches plan
Ends whenThe rollout is done and the flag is deletedThe plan is retired
Fails expensively whenRarelyStuck on: revenue leaks. Stuck off: churn

Key takeaway

If changing the pricing page should change who has access, that gate is an entitlement and it must resolve from the plan. If shipping the code should change who has access, that gate is a flag and it should be gone in a month.

The mechanism, concretely

An entitlement resolves from a published plan version. The version carries its items: features, limits and quotas. When a session loads, the workspace's current plan is read, the items come with it, and the checks in the UI read from that cached set. No extra request per render, and no separate place where "Pro includes analytics" is written down a second time.

Which version is not a detail. A subscription stays pinned to the version it was sold, so publishing new pricing leaves existing customers exactly where they are and a check that reads the plan's latest version instead hands them whatever you shipped last week.

One consequence worth knowing before it surprises you: the entitlements change on the next page load or session refresh, not instantly in an open tab. That is the correct behaviour for a commercial rule. Nobody needs an upgrade to appear mid-keystroke. It is the wrong behaviour for a kill switch, which is one more reason a kill switch is a flag and not an entitlement. On a downgrade the lag is longer than a session: the plan reports the change immediately while the features run to the end of the period.

Then there is the composition, which is where the distinction earns its keep:

<WhenWorkspaceFeatureEnabled slug="ai-generation">
  <WhenPermission permission={Permission.WORKSPACE_BILLING_MANAGE}>
    <WhenCreditsAvailable min={10}>
      <GenerateButton />
    </WhenCreditsAvailable>
  </WhenPermission>
</WhenWorkspaceFeatureEnabled>

Three gates, three different questions. Does the plan include AI generation? Is this member allowed to spend? Are there at least 10 credits? Entitlement, permission, balance. They nest because they are independent, and they are independent because each one has a different owner and a different reason to change. Collapsing them into one flag called can-generate would work for exactly as long as nobody changes a plan, a role or a price.

When an entitlement is the wrong tool

A beta rollout. A percentage ramp. A kill switch for a feature that is misbehaving in production. An experiment where half of one plan sees a new onboarding. None of these have anything to do with what the customer paid for, and encoding them as plan items pollutes the pricing model with engineering state. Use a flag. Delete it afterwards.

When a flag is the wrong tool

Anything that appears on the pricing page. If the word is in a plan comparison table, it is an entitlement, whatever tool currently gates it. The failure mode of using a flag here is slow: it works fine, then a plan changes, then someone updates most of the flags, then a customer on the old plan keeps a feature for four months because one flag was missed. That is not a bug in the flag tool. It is a flag being asked to remember something only the plan knows.

What this is not

An entitlement is not a permission. The plan entitles the workspace to billing management; the role decides which member may do it. And an entitlement is not a quota, although a quota is attached to one: the plan entitles the workspace to api-calls, and the quota is the number. The quota side of that, and the difference between a quota and a credit, is the sibling post: quotas are not credits.

BuildBase resolves plan-tied features from the plan version and user-targeted features from a list, under one feature flags module, and the reference shows both. The distinction above is the same whatever you build it on. The naming is on us.

billing
feature-flags
entitlements
plans

Frequently Asked Questions

Are entitlements the same as feature flags?

No. A feature flag is an engineering control that decouples deploying code from releasing it, and it is meant to be removed once the rollout is done. An entitlement is a commercial rule that says what a customer has access to under their plan, and it lives for as long as the plan exists. Both can gate the same component, which is why they get confused.

Can I use a feature flag tool for plan entitlements?

You can, and many teams do at first. It breaks the day a plan changes: every flag that encodes a plan has to be updated by hand, in the flag tool, by whoever remembers which flags mean which plan. An entitlement should resolve from the plan itself so that changing the plan changes access without a deploy or a flag edit.

Where should entitlement checks live, in the client or on the server?

Both, for different reasons. The client check decides what to render, so a customer sees an upgrade prompt instead of a broken button. The server check is the one that actually protects the resource, because a client check is a suggestion. If you only have budget for one, it is the server one.

What happens to entitlements when a customer downgrades?

They follow the new plan without anyone editing anything. The plan reports the downgrade immediately, the features already paid for run to the end of the billing period, and after that the new plan's set loads on the next page load or session refresh. That is the property that separates an entitlement from a flag: it is derived from the plan, not set independently. If a downgrade leaves a customer with access they no longer pay for once the period ends, the gate was a flag wearing an entitlement costume.

Put this into practice

The modules in this post are one console away. 7-day free trial, no credit card.

7-day free trialNo credit card requiredCancel anytime