Designing Plan-Based Feature Restrictions in a SaaS Application
Plan limits look simple in a pricing table and get messy in code. Free vs Pro vs Business is not one
if statement โ it is an entitlement system that must stay consistent across UI, API, jobs,
and support tools.
Define Entitlements as Data, Not Scattered Checks
I keep a single source of truth for what each plan allows:
const PLANS = {
free: { projects: 1, seats: 1, customDomain: false, export: false },
pro: { projects: 10, seats: 5, customDomain: true, export: true },
business: { projects: Infinity, seats: 50, customDomain: true, export: true }
};
Features read from this map (or a DB table synced from billing) instead of hardcoding plan names in fifty components.
Enforce on the Server โ Always
Hiding a button is UX. Blocking the API is security and billing integrity. Every restricted mutation checks entitlements server-side:
if (!entitlements.customDomain) {
return res.status(402).json({ error: 'upgrade_required', feature: 'customDomain' });
}
UI Should Explain the Wall, Not Pretend It Is Gone
- Show locked features with an upgrade CTA when discovery matters
- Hide features that would only confuse Free users
- Never silently no-op a click โ return a clear upgrade path
Limits Need Soft and Hard Behaviors
- Soft: warn at 80% of seat/project quota
- Hard: block create when at limit; allow read/edit of existing items
- Grace: optional short overage for annual customers during renewal glitches
Sync Billing Webhooks Carefully
Plan changes arrive asynchronously from Stripe/Paddle/etc. I treat webhook handlers as the authority that updates the local entitlement snapshot, then invalidate sessions or feature caches. Manual admin overrides exist for support, but they are audited.
Test Matrix Worth Automating
Free: cannot create 2nd project
Pro: can enable custom domain
Business: seat invite blocked at limit
Downgrade: excess resources become read-only
Webhook: plan upgrade unlocks API within seconds
Final Thoughts
Plan restrictions are a product surface and a security boundary. Centralize entitlements, enforce on the server, and make upgrade paths honest in the UI.
Written by A.M. Rinas ยท Published September 4, 2026