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

Caching Strategies and Cache Invalidation — The Complete Guide
CachingSystem DesignPerformance

Caching Strategies and Cache Invalidation — The Complete Guide

A practical guide to caching strategies (cache-aside, write-through, write-behind) and the cache invalidation techniques that keep them from serving stale data.

September 8, 2026Read more →
Database Indexing and Read Replicas — A Practical Guide
DatabasePostgreSQLSystem Design

Database Indexing and Read Replicas — A Practical Guide

How to choose the right database indexes, avoid the ones that quietly hurt write performance, and scale reads with replicas without introducing replication lag bugs.

September 8, 2026Read more →
Load Balancing and Stateless Service Design — A Practical Guide
System DesignLoad BalancingScalability

Load Balancing and Stateless Service Design — A Practical Guide

How load balancers distribute traffic, why stateless services are what actually makes horizontal scaling work, and how to fix the sticky-session traps that quietly reintroduce state.

September 8, 2026Read more →
Session Stores and Database Connection Pooling Explained
BackendRedisDatabase

Session Stores and Database Connection Pooling Explained

Why in-memory sessions break horizontally scaled apps, how to move session state to Redis correctly, and how connection pooling keeps your database from falling over under concurrent load.

September 8, 2026Read more →
Vertical vs Horizontal Scaling: How to Choose and Implement Each
System DesignScalabilityArchitecture

Vertical vs Horizontal Scaling: How to Choose and Implement Each

A practical comparison of vertical and horizontal scaling — what each actually fixes, where each breaks down, and the architecture changes horizontal scaling requires that most guides skip.

September 8, 2026Read more →
AI Agent Guardrails and Safety — Preventing Prompt Injection and Runaway Actions
Ai Agent SafetyPrompt Injection DefenseAgent Guardrails

AI Agent Guardrails and Safety — Preventing Prompt Injection and Runaway Actions

Build practical guardrails for AI agents — prompt injection defenses, destructive-action confirmation, iteration caps, and permission scoping.

September 7, 2026Read more →

Trending Topics