Usage Limits
Enforce per-plan feature quotas with monthly usage tracking, visual meters, and automatic resets.
Add per-plan feature limits — e.g., "100 API calls on Free, unlimited on Pro" — with monthly auto-reset, a visual usage dashboard, and checkLimit() / incrementUsage() helpers.
Files
lib/features/usage-limits.ts — Plan limit configuration (planLimits)
lib/features/usage-tracker.ts — checkLimit(), incrementUsage(), getUsage()
app/api/usage/route.ts — GET current usage + limits for authenticated user
hooks/features/use-usage.ts — useUsage() TanStack Query hook
components/features/usage-limits/
usage-meter.tsx — Single feature progress bar (amber at 60%, red at 85%)
usage-dashboard.tsx — Grid of all usage metersThe UsageRecord Prisma model is already in prisma/schema.prisma.
Setup
1
Configure plan limits
Edit lib/features/usage-limits.ts:
export const planLimits = {
FREE: { apiCalls: 100, projects: 3 },
STARTER: { apiCalls: 1000, projects: 10 },
PRO: { apiCalls: -1, projects: -1 }, // -1 = unlimited
ENTERPRISE: { apiCalls: -1, projects: -1 },
}2
Add limit checks to API routes
import { checkLimit, incrementUsage } from "@/lib/features/usage-tracker"
import { getRequiredSession } from "@/lib/auth-utils"
import { NextResponse } from "next/server"
export async function POST(req: Request) {
const session = await getRequiredSession()
const { allowed } = await checkLimit(session.user.id, session.user.plan, "apiCalls")
if (!allowed) {
return NextResponse.json(
{ success: false, error: "Limit reached. Upgrade your plan." },
{ status: 429 }
)
}
// ... process request ...
await incrementUsage(session.user.id, "apiCalls")
return NextResponse.json({ success: true, data: result })
}3
Show usage in the dashboard
import { UsageDashboard } from "@/components/features/usage-limits/usage-dashboard"
// In any dashboard page
<UsageDashboard />Or individual meters:
import { UsageMeter } from "@/components/features/usage-limits/usage-meter"
<UsageMeter feature="apiCalls" current={47} limit={100} label="API Calls" />API
GET /api/usage
Returns current usage and limits for the authenticated user:
{
"success": true,
"data": {
"plan": "FREE",
"features": [
{ "feature": "apiCalls", "current": 47, "limit": 100 },
{ "feature": "projects", "current": 2, "limit": 3 }
]
}
}How Usage Resets
Usage is tracked by period (e.g., "2026-03"). The getCurrentPeriod() function in usage-tracker.ts returns the current month string — usage automatically resets when a new month begins.
Environment Variables
None required.
Verification
- Set
FREE.apiCalls: 3temporarily inplanLimits - Call your API route 4 times as a FREE user
- The 4th request should return
429with "Limit reached" - Upgrade the user's plan to PRO — requests should succeed immediately
- Reset
planLimitsto production values