Entitlements — Decoupling What Customers Can Do from What They Pay

Scattered through most SaaS codebases is the same bug factory: `if plan == "pro"` checks guarding features. They work until the first pricing change, when "pro" splits into three plans, grandfathered customers keep old capabilities, sales grants an exception, and a trial needs temporary access — and suddenly product code is re-implementing billing logic badly. Entitlements are the missing layer: a dedicated system answering "may this customer do X?" so that product code never asks about plans at all.

Post 4 built the subscription; this post builds the layer between it and the product — small in code, outsized in how much future pain it prevents.

The core move: capabilities, not plans

The design has three parts, and the discipline is keeping them separate:

Plans then become bundles of grants — a mapping owned by the pricing catalog (post 2), versioned like everything else there. When pricing changes, the bundle mapping changes; product code, which only ever asked about features, doesn’t notice. That indirection is the entire point: pricing can now be re-packaged freely — the business’s favorite activity — without a product deploy.

The runtime: fast, cached, and fail-deliberate

Entitlement checks sit on hot paths — sometimes per-request — so the resolution above can’t be a five-table join at runtime. The standard shape: resolve on change (subscription transitions, grant edits trigger re-resolution), cache the flattened result (account → feature-values) close to the product, and propagate changes via events with seconds-not-hours staleness budgets. Two policies need deciding, not defaulting: failure mode — when the entitlement service is unreachable, failing closed protects revenue and failing open protects experience, and the right answer differs per feature (fail open on a UI nicety, closed on expensive API access); and grace semantics — post 4’s past-due state typically degrades entitlements gradually (warn, then limit, then suspend) rather than cliff-edge, and that ladder is grant logic, not scattered ifs.

Quota features add the loop with metering (post 3): the meter counts consumption; entitlements hold the allowance; enforcement compares the two — with the streaming meter’s near-real-time totals, since quota enforcement is exactly the product surface approximate-but-fast was built for. The invoice still bills from batch truth; the quota gate just needs to be roughly right now.

What good entitlements buy later

The payoffs stack up quietly. Experimentation: packaging tests (feature X in plan A vs B) become grant-bundle changes with cohorts, no code. Sales flexibility: exceptions are explicit grants with sources, owners, and expiry — visible, auditable, revocable — instead of folklore. Trials and previews: time-boxed grants, same machinery. Migrations: moving customers between price versions (post 2) or plan structures is a grant-mapping exercise with a diffable before/after per account. Support: “why can’t this customer export?” is answered by reading their resolved grants, not by archaeology across plan checks. And one boundary note: entitlements answer commercial permission (did they pay for it?), not security permission (are they allowed by role?) — keep it beside, not inside, your authorization system; conflating them couples billing changes to security reviews.

The takeaway: entitlements replace if plan == "pro" with a layer of features (boolean / limit / quota), grants (valued, sourced, time-boxed), and resolution behind a single fast check — with plans demoted to versioned bundles of grants owned by the catalog. Resolve on change, cache flat, pick failure modes and past-due degradation ladders per feature, and let quotas enforce against the streaming meter while invoices bill from batch truth. The reward is the decoupling itself: pricing re-packages freely, exceptions become auditable, and product code never learns what a plan is.

Key takeaways

Further reading

Sources & References

the enforcement family entitlements belong to
the runtime-flag machinery entitlements resemble