BoilerplateHub

Next.js + Supabase + Auth.js + Stripe

Next.js with Supabase, Auth.js and Stripe is the assembled version of the default stack: Postgres from Supabase, OAuth from Auth.js, and billing you write yourself. Nothing here is bundled, so every piece stays replaceable. It suits a team that wants social login working this week and accepts designing roles and billing state around it.

Next.js SupabaseAuth.jsStripe

Database

Supabase

The Supabase Postgres holds application data and, through the Auth.js adapter, the users, accounts and sessions tables the adapter defines. That schema belongs to the adapter, so extend it with your own tables joined on user ID rather than bolting columns onto it. The Stripe mirror goes in one of those side tables, which keeps an adapter version bump from colliding with billing fields you added by hand.

Authentication

Auth.js

Auth.js is largely a provider and callback layer, so what arrives quickly is a dozen OAuth logins and very little else. Roles, invitations and team membership remain yours to design. Choose deliberately between JWT and database sessions: the database strategy costs a query per request but lets you revoke a session and read the Stripe plan in the same trip, which is usually the correct trade once real money is involved.

Payments

Stripe

Checkout sessions are created in a route handler with the signed-in user attached to the Stripe customer through metadata, and everything after that is conventional: webhooks update the mirror, entitlement reads hit Postgres. Remaining merchant of record means tax treatment, invoice content and refund policy are decisions your business makes and your code implements, which is freedom in exact proportion to the accounting you are willing to carry.

What to watch out for

The session callback is where people stash the plan name so components can read it, and a JWT session then caches that plan until the token rotates. Someone who upgrades keeps seeing the old tier and blames the payment, not the token. Read entitlements from Postgres at request time, or force a session refresh when the user returns from checkout, instead of treating an identity token as a billing cache.

Boilerplates close to this stack

Matched on Next.js plus the parts of this stack our catalog tags. Each card shows which pieces actually line up, so you can see how much you would still wire yourself.

A CLAUDE.md for this stack

The rules that matter for this combination specifically, including who owns entitlement state. Adapt the commands to your repository before committing it.

CLAUDE.md
# CLAUDE.md

This project is a Next.js SaaS on Supabase, Auth.js and Stripe.

## Stack

- Framework: Next.js
- Database: Supabase
- Auth: Auth.js
- Payments: Stripe

## Boundaries

- Never edit a migration that has already run. Write a new one.
- Never hardcode Stripe price or product identifiers in components. They belong in config.
- Never trust a client-supplied user id. Read the session from Auth.js on the server.
- Treat webhook handlers as idempotent. The same event will arrive twice.

## Entitlements

- Stripe is the source of truth for what a customer paid for.
- The database mirrors that state; it never decides it.
- Any check for "can this user do X" reads the mirrored entitlement, not a live API call.

## Before you say a change is done

- The app builds.
- Tests pass.
- No secret, key or webhook signing secret appears in a committed file.

Related stacks