Stripe Subscriptions in Next.js — Complete Setup Guide
Add Stripe subscription billing to a Next.js app with Checkout, webhooks for plan sync, and a customer portal for self-serve upgrades and cancels.

Stripe Checkout handles the payment UI, but a working subscription system needs webhooks to keep your database in sync and a way for customers to manage their own billing — this guide covers all three pieces end to end.
Step 1: Install Stripe and Set Up Products
Create a Product and a recurring Price in the Stripe Dashboard (or via API), then store the price ID in your app's config.
Step 2: Create a Checkout Session
The metadata.userId field is what lets the webhook handler later map a Stripe event back to a row in your own database.
Step 3: Handle Webhooks to Sync Subscription Status
Verifying with constructEvent using the raw body (not a parsed JSON object) is mandatory — Stripe signs the exact byte payload, so any middleware that parses the body before this handler runs will break signature verification.
Step 4: Gate Features Using the Synced Status
Checking a local database field instead of calling Stripe's API on every page load keeps feature gates fast and avoids rate limits.
Step 5: Let Customers Manage Billing via the Customer Portal
The portal handles upgrades, downgrades, cancellations, and payment method updates — all of which fire the same customer.subscription.updated webhook your handler already processes, so no extra sync logic is needed.
Key Takeaways
Checkout Sessions handle subscription payment UI, but webhooks — verified with the raw request body and signing secret — are the only reliable way to keep subscription status in your own database, and the Stripe Customer Portal removes the need to build any self-serve billing UI of your own.






