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.ts

Server-side entitlement checks: requireEntitlement(), hasEntitlement().

/hooks/use-entitlements.ts

Client-side hook for checking entitlements in React components.

/components/FeatureGate.tsx

UI component that conditionally renders content based on entitlements.

/components/UpgradePrompt.tsx

Upgrade prompt component shown when users lack required entitlements.

/app/api/user/entitlements/route.ts

API endpoint that returns user's current entitlements.

Usage

Server-Side (Pages & API Routes)

Use requireEntitlement() for full page protection:

typescript
import { requireEntitlement } from "@/lib/auth-utils";

export default async function ProPage() {
  const user = await requireEntitlement("pro_features");
  return <ProContent />;
}

Use hasEntitlement() for conditional logic:

typescript
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:

tsx
import { FeatureGate } from "@/components/FeatureGate";

<FeatureGate entitlement="api_access">
  <ApiKeyGenerator />
</FeatureGate>

Or use the hook directly:

tsx
"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:

  1. Add to /prisma/seed.ts:
    typescript
    await prisma.entitlement.upsert({
      where: { name: "your_feature" },
      update: {},
      create: {
        name: "your_feature",
        displayName: "Your Feature",
        description: "What it does",
      },
    });
  2. Link to plan(s) in the seed script
  3. Run pnpm db:seed
  4. Update PLAN_REQUIREMENTS in /components/UpgradePrompt.tsx if you want custom upgrade messaging
  5. Use in your code with FeatureGate or entitlement checks

Default Entitlements

basic_access

Dashboard and basic features. Included in Free and Pro plans.

pro_features

Advanced tools. Pro plan only.

api_access

REST API endpoints. Pro plan only.

priority_support

Faster 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