Entitlements
Feature flags that control access to parts of your app. Users get entitlements through their subscription plan.
What This System Does
The entitlements system:
- Gates features based on subscription plans
- Provides server and client-side checking APIs
- Automatically syncs with subscription changes
- Allows granular feature control
- Enables multiple plans to share entitlements
Why It Exists
Entitlements provide a flexible way to gate features without hardcoding plan names. You can add or remove features from plans without code changes, and multiple plans can share the same entitlements.
When You Need to Care About It
You'll use entitlements when:
- Gating features behind subscription tiers
- Showing upgrade prompts to free users
- Protecting API routes or pages
- Adding new features that require specific plans
Key Concepts
Check Entitlements, Not Plans
Always check for entitlements, not plan names. This allows you to modify which plans include which features without code changes.
✅ Good
if (hasEntitlement("api_access"))❌ Bad
if (user.plan === "pro")Automatic Sync
Entitlements automatically sync with subscriptions. When a subscription is activated, entitlements are granted. When cancelled, they're revoked.
Default Entitlements
Users without active subscriptions get the Free plan's entitlements (typically just basic_access).
Important Files
/lib/auth-utils.tsServer-side entitlement checks: requireEntitlement(), hasEntitlement().
/hooks/use-entitlements.tsClient-side hook for checking entitlements in React components.
/components/FeatureGate.tsxUI component that conditionally renders content based on entitlements.
/components/UpgradePrompt.tsxUpgrade prompt component shown when users lack required entitlements.
/app/api/user/entitlements/route.tsAPI endpoint that returns user's current entitlements.
Usage
Server-Side (Pages & API Routes)
Use requireEntitlement() for full page protection:
import { requireEntitlement } from "@/lib/auth-utils";
export default async function ProPage() {
const user = await requireEntitlement("pro_features");
return <ProContent />;
}Use hasEntitlement() for conditional logic:
import { hasEntitlement } from "@/lib/auth-utils";
export default async function Dashboard() {
const hasPro = await hasEntitlement("pro_features");
return hasPro ? <ProDashboard /> : <FreeDashboard />;
}Client-Side (React Components)
Use the FeatureGate component:
import { FeatureGate } from "@/components/FeatureGate";
<FeatureGate entitlement="api_access">
<ApiKeyGenerator />
</FeatureGate>Or use the hook directly:
"use client";
import { useEntitlements } from "@/hooks/use-entitlements";
function MyComponent() {
const { hasEntitlement, loading } = useEntitlements();
if (loading) return <Spinner />;
if (!hasEntitlement("pro_features")) return <UpgradePrompt />;
return <ProFeature />;
}Adding New Entitlements
To add a new entitlement:
- Add to
/prisma/seed.ts:typescriptawait prisma.entitlement.upsert({ where: { name: "your_feature" }, update: {}, create: { name: "your_feature", displayName: "Your Feature", description: "What it does", }, }); - Link to plan(s) in the seed script
- Run
pnpm db:seed - Update
PLAN_REQUIREMENTSin/components/UpgradePrompt.tsxif you want custom upgrade messaging - Use in your code with
FeatureGateor entitlement checks
Default Entitlements
basic_accessDashboard and basic features. Included in Free and Pro plans.
pro_featuresAdvanced tools. Pro plan only.
api_accessREST API endpoints. Pro plan only.
priority_supportFaster support response. Pro plan only.
What You Can Customize
FeatureGate Component
Located at /components/FeatureGate.tsx. Customize loading states, locked UI, or add custom fallback content.
UpgradePrompt Component
Located at /components/UpgradePrompt.tsx. Customize messaging, button text, or add custom upgrade flows.
PLAN_REQUIREMENTS Mapping
In UpgradePrompt.tsx, map entitlements to plan names for custom upgrade messaging.
What NOT to Touch
/lib/auth-utils.ts
Core entitlement checking logic. Marked with 🔒 CORE SYSTEM. Don't modify the core functions.
/hooks/use-entitlements.ts
Client-side hook logic. Ensures consistent entitlement checking across components.
Entitlement → Plan Relationship
The database relationship structure is critical. Don't modify how entitlements link to plans.
Related Sections
- Authentication - User sessions required for entitlement checks
- Payments - Subscriptions grant entitlements
- Database - Entitlement and plan data models