How to add Stripe to Next.js (App Router, 2026)

How to add Stripe to Next.js (App Router, 2026)
Stripe in Next.js looks like a five-minute job until you hit the parts that only matter under real invoices: webhook idempotency, the customer portal, failed payments, proration. This is the shape of the integration that survives the first month of production.
The three modules you need
A working Stripe wiring in App Router is rarely a single file. Split it into three so each piece has one job.
1. Server-only Stripe client. Mark the module import "server-only" so a stray client component cannot import your secret key. Construct the client lazily, read process.env.STRIPE_SECRET_KEY inside a function, not at the top of the module, so a missing env var does not crash next build during Collecting page data. The lazy Proxy pattern we documented separately works here: build passes, runtime throws clearly if the key is missing.
2. Checkout Route Handler. A POST /api/checkout/route.ts that calls stripe.checkout.sessions.create({...}) and returns the session URL. Always pass client_reference_id (your internal user or workspace id), set customer_email when you have one, and use metadata for the plan id you can read back in the webhook. Pin apiVersion in your client config and hedge model claims to your current Stripe API version (verify in current Stripe docs, they ship breaking changes more often than the libraries imply).
3. Webhook Route Handler. A POST /api/webhooks/stripe/route.ts that verifies the signature with stripe.webhooks.constructEvent(rawBody, signature, secret). Read the raw body with await req.text(), not req.json(), JSON parsing strips bytes the signature was computed over. Without raw-body verification, every "test" with --forward-to works and every production webhook fails.
What survives production
The defaults Stripe shows you in the docs are not enough. Three additions you will regret skipping:
- Idempotency keys on writes. Pass
idempotencyKey: <stable-id>onstripe.subscriptions.update,stripe.customers.create, and any other write you might retry. A network hiccup on retry without one creates duplicate customers and double-charges. - Webhook handler runs in
<2s, then offloads. Stripe expects a 2xx fast. Do the signature check, write a row to yourstripe_eventstable with the event id as the primary key (this is your idempotency boundary), and return 200. Heavy work, sending email, updating downstream services, runs in a queue or a follow-up worker. - Customer portal link. Add a
POST /api/billing/portalthat callsstripe.billingPortal.sessions.create({ customer: customerId, return_url }). The portal handles cancellation, plan changes, invoice history, payment method updates. Without it, every cancellation becomes a support ticket.
For credits and usage-based billing on top of subscriptions, the metering layer is where most templates stop short. /features/stripe-credits walks through the credit ledger pattern, debit on token use, top up via webhook on invoice.paid, expose the balance on the dashboard.
When to skip raw Stripe
Raw Stripe gives you control. It also gives you the EU VAT, sales tax, chargeback flow, and 1099-K reporting surface. For digital goods sold globally to consumers and small businesses, a merchant of record (Paddle, Polar, Lemon Squeezy) handles all of that for a percentage point on top of fees. If you are a one-person team selling worldwide, the MoR route trades margin for hours of compliance work, usually the right trade.
If you want this wired end-to-end, Stripe client, checkout, webhooks, customer portal, credits, and a working dashboard, both /saasforge-core (subscriptions + portal + webhooks + audit) and /saasforge-ai (subscriptions + credit metering) ship it as production code. Start there if you would rather edit a working integration than build one from a Stripe docs page.
Ship this with a Boilerlykit template
Skip the wiring. Each template ships the patterns from this article as production code with MDX docs.
SaaSForge AI
For founders shipping assistants, doc search, or writing tools: models, uploads, metering, and billing in one codebase.
- Streaming chat (Claude & OpenAI)
- RAG pipeline with pgvector
- Per-token credit metering & cost calc
SaaSForge Core
For B2B tools where accounts, roles, and audit trails matter as much as the feature list.
- Multi-tenant workspaces with RLS
- 4-role RBAC + granular permissions
- Stripe subscriptions (3 tiers)