/library / template-nextjs-saas-starter
templateWeb app

Next.js 16 SaaS starter (Stripe + magic-link auth)

Opinionated CLAUDE.md for a Next.js 16 + Tailwind v4 SaaS with Stripe billing, Resend magic-link auth, and Vercel Postgres. Drop in your project root, edit five lines, ship.

use whenStarting a new SaaS with Next.js 16. You want billing + auth working day one without picking 12 libraries.

May 15, 20262,680 bytesnextjstailwindstripesaasvercel

[Your SaaS Name]

[One-line description of what your app does. Replace this on day one.]

Source of truth

Production on Vercel. vercel pull before any local work to mirror env + branch state.

Tech stack

Next.js 16 (App Router) + React 19 + Tailwind v4. Server Actions for every mutation. Postgres via Vercel Postgres (Neon underneath). Magic-link auth (Resend + signed JWT cookie). Stripe Checkout + Billing Portal for subscriptions. Vercel for hosting + cron.

Deploy

git push to main triggers Vercel auto-deploy. Preview URLs per PR. Production gated by manual promote on Vercel dashboard until you trust your CI.

File map

  • app/ Next.js routes
  • app/(marketing)/ public: /, /pricing, /privacy, /terms
  • app/(app)/ authed: /dashboard, /settings, /billing
  • app/api/auth/[...]/route.ts magic-link send + verify
  • app/api/stripe/webhook/route.ts Stripe webhook receiver
  • lib/db.ts Postgres client + typed query helpers
  • lib/auth.ts JWT cookie sign/verify
  • lib/stripe.ts Stripe SDK config + price cache
  • db/schema.sql initial schema
  • components/ React components, server-first

.env keys

  • DATABASE_URL Vercel Postgres connection string
  • JWT_SECRET random 32-byte hex
  • RESEND_API_KEY
  • RESEND_FROM_EMAIL verified sender (hello@yourdomain.com)
  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • STRIPE_PRICE_ID your default plan price ID
  • NEXT_PUBLIC_SITE_URL https://yourdomain.com

Hard rules

  • Mutations are Server Actions, never API routes (except Stripe webhook).
  • All Postgres queries go through lib/db.ts. No raw pg in components.
  • JWT cookie is httpOnly, secure, sameSite: 'lax'. Never read on the client.
  • Stripe webhook signature is verified before any DB write.
  • Pricing page reads from Stripe API at build time. No hardcoded prices in JSX.
  • No em-dashes anywhere in user-facing copy (Pangram flags them).
  • Run a real Lighthouse pass on every customer-facing route before DNS attach.

Recent significant changes

  • 2026-05-15: Scaffolded. Locked: Next 16, Tailwind v4, Resend for magic links (not NextAuth, which got bloated), Vercel Postgres (not Supabase, billing simpler).

Next session: start here

  1. Create Vercel project. Link Vercel Postgres.
  2. Create Stripe products + prices for your plans. Save STRIPE_PRICE_ID.
  3. Set verified domain in Resend, save RESEND_FROM_EMAIL.
  4. Copy .env.example -> .env.local. Fill in.
  5. Apply db/schema.sql via vercel postgres connect.
  6. npm run dev. Test the magic-link sign-in end to end.
  7. Test the Stripe webhook via stripe listen --forward-to localhost:3000/api/stripe/webhook.
  8. Smoke-test a real subscribe -> webhook -> DB write before launch. Critical-flow gate.

Get the next CLAUDE.md in your inbox.

One new template every week, plus occasional case studies.