DEV Community

huangyongshan46-a11y
huangyongshan46-a11y

Posted on

How to Check Subscription Plans in Next.js (Prisma + Stripe)

After Stripe checkout and webhooks, you need to gate features by plan. Here is the pattern.

import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { redirect } from "next/navigation";

async function requirePro() {
  const session = await auth();
  if (!session?.user) redirect("/login");
  const sub = await db.subscription.findUnique({ where: { userId: session.user.id } });
  const isPro = sub?.status === "ACTIVE" && (sub.plan === "PRO" || sub.plan === "ENTERPRISE");
  if (!isPro) redirect("/billing");
  return sub;
}
Enter fullscreen mode Exit fullscreen mode

Call at the top of any server component. Non-Pro users get redirected to billing.

Usage-based limits

async function checkAILimit(userId: string) {
  const sub = await db.subscription.findUnique({ where: { userId } });
  const limits: Record<string, number> = { FREE: 50, PRO: 1000, ENTERPRISE: -1 };
  const limit = limits[sub?.plan ?? "FREE"];
  if (limit === -1) return true;

  const startOfMonth = new Date();
  startOfMonth.setDate(1); startOfMonth.setHours(0,0,0,0);

  const count = await db.message.count({
    where: { conversation: { userId }, role: "USER", createdAt: { gte: startOfMonth } },
  });
  return count < limit;
}
Enter fullscreen mode Exit fullscreen mode

In an API route

const canChat = await checkAILimit(session.user.id);
if (!canChat) return NextResponse.json({ error: "Limit reached" }, { status: 429 });
Enter fullscreen mode Exit fullscreen mode

Enum-based plans + count query = scales from MVP to thousands of users.

Full implementation: LaunchKit ($49)

GitHub

Top comments (0)