Orbit
Next.js Stripe boilerplate

A Next.js Stripe boilerplate that handles every webhook.

Wiring Stripe by hand is a week you don't get back. Orbit's paid tier ships Next.js 16 + Stripe with checkout sessions, customer portal, signature-verified webhooks, an append-only billing event ledger, and the multi-tenant primitives — workspaces, PBAC, audit logs — that make subscriptions actually map to your product. Next.js and Stripe both live in the paid tier; the free public starter is TanStack Start + better-auth without billing.

$npx create-orb@latest
What you get
Next.js 16 frontend, idiomatic

App Router, React 19, server components, route handlers. The billing settings UI lives in /d/$workspaceSlug/workspace/settings/billing and is gated by workspace.billing.manage.

Stripe, end to end

Checkout sessions for upgrades, customer portal for plan changes and invoices, webhook receiver that verifies the signature and translates events into domain updates inside a Unit of Work.

Append-only event ledger

Every billing event Stripe sends is persisted to a billing_events table. Idempotent, replayable, auditable. If a webhook fires twice, your subscriptions don't double-flip.

Workspace-scoped subscriptions

A subscription belongs to a workspace, not a user. Ownership transfer keeps the customer ID with the workspace. The customer portal link is scoped to the right Stripe customer with no impersonation gymnastics.

Provider port

Stripe is one adapter behind a BillingProvider port. Polar and Dodo are the others. Pick at scaffold; switch later by replacing one file. Product code never imports the Stripe SDK.

Local webhooks that just work

Built-in smee.io webhook tunnel forwards Stripe events to localhost:4002 in dev. No ngrok dance, no stripe listen process to babysit.

FAQ
Stripe Checkout or embedded Elements?
Checkout sessions, with the customer portal for self-serve plan changes and invoices. Embedded Elements is overkill for the 95% of SaaS use cases this template targets.
How do you verify webhooks?
The Stripe adapter verifies the Stripe-Signature header against your webhook secret on every request. Handlers run inside a Unit of Work, so domain events fire atomically with the DB write.
Can I switch from Stripe to Polar or Dodo later?
Yes — that's the whole point of the BillingProvider port. Pick one at scaffold; if you change your mind, swap the adapter file. The rest of the codebase doesn't notice.
How do plans get defined?
There's a guide for it. Plans live in code (typed), price IDs are env vars, and the upgrade button kicks off a checkout session. Audit log records every plan change.
Does it work with Next.js 14 or only Next.js 16?
The shipped template is Next.js 16. The architecture is plain App Router + route handlers, so backporting is straightforward, but we don't ship a 14 variant.