Decorative background gradient
Back to Blog
Stripe Subscriptions NextjsStripe WebhooksSaas Billing

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 Subscriptions in Next.js — Complete Setup Guide

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

bash

Create a Product and a recurring Price in the Stripe Dashboard (or via API), then store the price ID in your app's config.

ts

Step 2: Create a Checkout Session

ts

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

ts

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

ts

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

ts

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.

Frequently Asked Questions

Why do I need webhooks if Checkout already redirects to a success URL?

The success URL redirect only fires if the user's browser completes the round trip — if they close the tab, lose connection, or the browser crashes right after payment, your app never learns the subscription was created. Webhooks are delivered directly from Stripe's servers regardless of what happens to the user's browser, making them the only reliable source of truth.

How do I verify a Stripe webhook is actually from Stripe?

Read the raw, unparsed request body and pass it along with the stripe-signature header to stripe.webhooks.constructEvent() with your webhook signing secret. Never trust a webhook payload that hasn't been verified this way — anyone could POST a fake event to your endpoint otherwise.

How do I let users cancel or upgrade their own subscription?

Create a Stripe Billing Portal session (stripe.billingPortal.sessions.create) and redirect the user to the returned URL. Stripe's hosted portal handles plan changes, cancellations, and payment method updates without you building any of that UI, and it fires the same webhooks your app already listens to.

Where should I store subscription status in my own database?

On your user (or organization) table, store the Stripe customer ID and a status field (active, past_due, canceled) kept in sync via webhooks. Checking this local field to gate features is far faster and more reliable than calling the Stripe API on every request.

Working on something similar? Take a look at my services and case studies, or book a free call to talk about your idea.

Related Articles

Silent Tool Failures in AI Agents — Why Your Agent Lies About Success
Ai Agent ReliabilityTool Call FailuresLlm Error Handling+1 more

Silent Tool Failures in AI Agents — Why Your Agent Lies About Success

Most AI agent bugs never throw an error — the tool call "succeeds" with empty, truncated, or stale data and the agent confidently reports the task as done. Here's how to catch failures that don't look like failures.

September 22, 2026Read more →
AI Coding Agents Compared in 2026 — Claude Code vs Cursor vs GitHub Copilot
Claude Code Vs CursorAI Coding AgentsGithub Copilot

AI Coding Agents Compared in 2026 — Claude Code vs Cursor vs GitHub Copilot

Compare Claude Code, Cursor, and GitHub Copilot for real development work — agentic workflows, codebase understanding, pricing, and which fits your team.

September 18, 2026Read more →
Best Authentication Libraries for Next.js in 2026 — Clerk vs Auth.js vs Better Auth
Nextjs AuthenticationClerk Vs NextauthBetter Auth

Best Authentication Libraries for Next.js in 2026 — Clerk vs Auth.js vs Better Auth

Compare Clerk, Auth.js (NextAuth), and Better Auth for Next.js — setup effort, hosted UI, pricing, and which fits your app.

September 18, 2026Read more →
Best Error Monitoring & Analytics Tools for Next.js in 2026 — Sentry vs PostHog vs Vercel Analytics
Nextjs Error MonitoringSentry Vs PosthogWeb Analytics

Best Error Monitoring & Analytics Tools for Next.js in 2026 — Sentry vs PostHog vs Vercel Analytics

Compare Sentry, PostHog, and Vercel Analytics for a Next.js app — error tracking, product analytics, session replay, and pricing.

September 18, 2026Read more →
How to Add AI Features to an Existing Web App (Without a Rebuild)
Add AI To Existing AppAI SaaS FeaturesOpenAI API Integration

How to Add AI Features to an Existing Web App (Without a Rebuild)

A practical guide to adding real AI features, like matching, extraction, and automation, to a web app or SaaS product you already have, without rebuilding it from scratch.

September 16, 2026Read more →
AI Agent Observability and Tracing in Production
Ai Agent ObservabilityLlm TracingAgent Monitoring+2 more

AI Agent Observability and Tracing in Production

Why logging inputs and outputs isn't enough for AI agents in production — and how trace-level observability catches failures evals and logs miss.

September 14, 2026Read more →

Trending Topics