Integrates Better Auth with email/password, Google, GitHub, and magic link login, with sessions stored in PostgreSQL
ai-saas-starter — Next.js SaaS Template
By nikandr-surkov
A Next.js-based AI SaaS starter template that integrates Better Auth authentication, Stripe subscriptions, a credit ledger, and AI image generation, and provides context files for coding agents.
Explore the design
Compare the page layouts and mobile experience. Open any screenshot for a closer look.
Actual screenshot captured by the server browser.
All pages & views 2
Screenshots show visual appearance; interactive behavior may differ.
What stands out
A quick read of the recorded project description.
Stripe subscriptions and one-time top-ups, webhooks verify the raw request signature, and subscription status is written by a single sync function
Append-only credit ledger using unique idempotency keys, with the database rejecting negative balances and zero-amount rows, and spending using conditional UPDATE to prevent concurrent overspending
AI image generation flow includes rate limiting, credit deduction, and automatic refunds on failure, with model switching via environment variables
Provides files such as AGENTS.md, path-scoped rules, skills, and hooks so coding agents like Claude Code and Cursor can extend the project under constraints
Includes Vitest unit/integration tests and Playwright end-to-end tests covering ledger behavior, webhook signatures, double-spend races, and other scenarios
Template Details
This is an AI SaaS starter template for Next.js. The code is publicly available on GitHub under the MIT license, and the demo site can be registered and actually run. The template pre-implements common paid paths such as authentication, Stripe subscriptions, a credit ledger, and AI image generation, letting developers build their own products on top of it.
Authentication supports email/password (with verification), Google, GitHub, and magic links, with sessions stored in PostgreSQL; the settings page provides password changes, account linking, and cascading-safe account deletion (which first cancels the Stripe subscription). Billing uses Stripe Checkout and Customer Portal as server-side operations, triggered by signature-verified webhooks, with subscription status written only by a single sync function, and plans, prices, and credit amounts centralized in a single configuration file.
The credits system uses an append-only credit_transactions table with unique idempotency keys: credits are granted on invoice payment, topped up at checkout, spent via conditional UPDATE to prevent concurrent overspending, and refunded as compensating rows, with the database rejecting negative balances and zero-amount rows. The AI generation flow is prompt → rate limiting (10 per minute) → deduct 1 credit → call the AI SDK to generate an image → storage (local directory in development) → history grid display; failed generations automatically refund credits.
The template also includes a set of context files for AI coding agents, such as AGENTS.md, path-scoped rules, skills, and hooks, to constrain agent behavior when modifying sensitive code like billing and databases. For testing, it provides Vitest unit/integration tests and Playwright end-to-end tests covering the credit ledger, webhook signature verification, double-spend races, and other scenarios.
Usage limitations: the template depends on external services (Stripe, Resend, AI providers, PostgreSQL, etc.), which may incur costs; third-party assets such as demo images, fonts, and icons require separate license verification; project materials mention an optional paid version, but this listing includes only the public free code.
Is it right for your project?
Use Cases
- Quickly build a prototype for an AI image generation SaaS product with subscription billing and credit consumption
- Reference its credit ledger and Stripe webhook idempotency handling in an existing Next.js project
- Prepare an AI-native codebase with clear security boundaries and path rules for coding agents
- Learn how to use an append-only ledger and database constraints to prevent credit overspending and duplicate grants
Suitable For
- Developers familiar with Next.js, TypeScript, and PostgreSQL who want to skip building authentication and payment foundations
- SaaS projects that need a credits or quota system and care about concurrency safety and idempotency
- Teams using coding agents like Claude Code and Cursor to assist development and wanting agents to follow project rules
- Learners who want to reference implementations of Stripe subscriptions, webhook verification, and refund paths
Getting started & customization
Use these recorded setup notes alongside the repository instructions for your chosen version.
- 1
Requires a Node.js environment and pnpm; clone the repository and run pnpm install
- 2
Start PostgreSQL 17 with docker compose, copy .env.example to .env, and generate BETTER_AUTH_SECRET
- 3
Run pnpm db:migrate to migrate the database, then pnpm dev to start the development server
- 4
Without Stripe, Resend, or OAuth keys configured, features degrade: the billing page shows a setup card, emails are silent, and OAuth buttons are hidden; set AI_MOCK=true for offline free image generation
- 5
To test Stripe locally, create test-mode prices, run pnpm stripe:listen, and write the whsec secret into .env
License & source material
Usage conditions & limitations
Free to use · keep license noticeThis listing covers the free version in the public repository under the MIT license; the free scope is that version's code and does not mean external services or third-party assets are free.
Must comply with when using
- You may use, modify, commercialize, and distribute this version's code for free.
- When distributing copies or substantial portions of the code, retain the original author's copyright notice and the full MIT license notice.
- The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.
Additional costs & items to verify
- Using Stripe billing requires creating test-mode prices in the Stripe dashboard (Pro $9/month, Ultra $29/month, one-time top-up $5) and writing the price IDs into environment variables; Stripe is an external paid service.
- Real image generation in production requires configuring an AI Gateway API key; that key's quota is a spending cap rather than a balance, and if the free quota is insufficient you must top up the gateway account or bring your own provider key.
- Sending email requires configuring a Resend API key and using a verified domain; Resend is an external service that may incur costs.
- Production deployment requires creating Blob storage on Vercel and setting it to public access, which is an external hosting service that may incur costs.
- Production deployment requires an external PostgreSQL service such as Neon, and you must create a project and provide a connection string yourself, which may incur costs.
- Legal pages (privacy policy, terms of service, etc.) are placeholders only and must be replaced with compliant text before launch.
- Capabilities such as teams, internationalization, admin dashboard, asynchronous task pipelines, video/audio generation, R2 storage, and MCP server are available only in the paid Pro version and are not included in the free repository.
- AI_MOCK simulation mode is rejected in production builds; production must connect to a real AI provider and bear the corresponding call costs.
- Project materials mention an optional paid version or features; this listing includes only the public free code and does not include paid upgrades.
- Demo images, fonts, icons, and other third-party assets must be checked under their respective licenses and cannot be judged solely by the code's MIT license.
- External services such as domains, hosting, databases, payments, or AI may charge additional fees.
View Original Text Basis
Permission is hereby granted, free of charge
Original License Text
Create three test-mode prices (Pro $9/mo, Ultra $29/mo, Top-up $5 one-time)
Original README
AI_GATEWAY_API_KEY`, `AI_IMAGE_MODEL` | AI Gateway; `AI_MOCK` stays UNSET
Original README
RESEND_API_KEY`, `EMAIL_FROM` | verified Resend domain
Original README
Blob store** — in the Vercel project: Storage → Create → Blob, with **Access: Public**
Original README
Neon** — create a project and copy BOTH connection strings
Original README
The legal pages are placeholders and the product on top is yours to build.
Original README
The paid kits are broader (teams, i18n, admin); the Pro version covers that ground.
Original README
https://github.com/nikandr-surkov/ai-saas-starter/blob/main/LICENSEhttps://github.com/nikandr-surkov/ai-saas-starter/blob/main/README.md`AI_MOCK=true` is refused in production builds
Original README
Compiled by DeepSeek based on repository license and README ·2026-10-01. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.
Project checks & description sources
Template Information
- Source platforms
- GitHub
- Documentation and maintenance reference score
- More documented · 92 / 100
- Technologies
- Next.js · React
- Website type
- SaaS · Starter
How this score is calculated
Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.
What to verify for this project
- Repository update recorded
- 2026-07-26
- Screenshot last checked
- 2026-10-01
A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.
The catalog identifies Next.js as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.
Use a selection guide →How this description was prepared
AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.
Automatically checked against source and license rules; no manual editorial review.
Inspect the recorded source material
SHA-256: 73d84b7085d6cace2b741127440e112abc5bd3997a4f185c959045e246766dc8
2026-10-01T01:24:29.685Z
Source file / repository# ai-saas-starter
The free, open-source AI SaaS boilerplate and starter kit for Next.js 16.
Auth, Stripe subscriptions, an append-only credits ledger, and AI image
generation — built as an AI-native repo that Claude Code, Cursor, and
Codex can extend without breaking the money paths.
[](https://github.com/nikandr-surkov/ai-saas-starter/actions/workflows/ci.yml)
[](LICENSE)
[](https://github.com/nikandr-surkov/ai-saas-starter/stargazers)
[Live demo](https://ai-saas-starter-six.vercel.app) ·
[Deploy guide](#deploy-to-production-vercel--neon) ·
[Pro version](https://nikandr.com)

## What is this?
- **This website is the demo** — [sign up](https://ai-saas-starter-six.vercel.app),
everything works.
- **The code is a free GitHub repo** — MIT, clone it.
- **You build YOUR product on top** — auth and payments are done.
A free, open-source SaaS boilerplate / starter kit for **Next.js 16 ·
React 19 · TypeScript strict · Better Auth · Drizzle + PostgreSQL ·
Stripe · AI SDK 6 · Tailwind v4 + shadcn/ui · Resend · Vitest +
Playwright**.
## See it
| | |
| --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|  |  |
| [Credits ledger on the dashboard — balance is SUM(amount), enforced](#whats-inside) | [AI image generation — 1 credit per image](#whats-inside) |
|  |  |
| [Busy state](#whats-inside) | [Plans from one config file](#whats-inside) |
|  |  |
| [Real Stripe checkout (test mode)](#stripe-locally) | [Auth + account settings](#whats-inside) |
## Why another SaaS boilerplate?
AI assistants are good at building product features and bad at the 20% that
loses money when improvised: webhook retries, concurrent spends, refund
paths, idempotency. This repo ships that 20% finished and tested — an
append-only credit ledger whose balance is enforced equal to
`SUM(amount)`, Stripe webhooks that verify raw-body signatures and survive
replays, a double-spend race test against real Postgres — plus the context
files (AGENTS.md, rules, skills, hooks) that keep an agent from quietly
unpicking any of it while you vibe-code the product on top.
## Quickstart (60 seconds)
```bash
git clone https://github.com/nikandr-surkov/ai-saas-starter.git my-app
cd my-app
pnpm install
docker compose up -d # Postgres 17
cp .env.example .env # fill in BETTER_AUTH_SECRET (openssl rand -base64 32)
pnpm db:migrate
pnpm dev
```
That boots with graceful degradation: no Stripe keys → billing page shows a
setup card; no Resend key → emails no-op with a console warning; no OAuth
keys → those buttons hide; `AI_MOCK=true` → image generation is free and
offline. Every variable is documented in [.env.example](.env.example).
## Quickstart for AI agents
Paste this into your coding agent:
```text
Clone https://github.com/nikandr-surkov/ai-saas-starter.git and get it
running: install deps, start Postgres via docker compose, create .env
from the example (generate the secret), migrate, run dev. Then read
AGENTS.md and brief me on the rules you're operating under.
```
Works with Claude Code, Cursor, Codex, Copilot, and Gemini CLI. The repo
briefs the agent itself — AGENTS.md, path-scoped rules, skills, hooks.
## What's inside
- **Auth** — email/password with verification, Google, GitHub, magic links.
Sessions live in your Postgres. Settings page with password change,
account linking, and cascade-safe account deletion (cancels the Stripe
subscription first).

- **Billing** — Stripe Checkout + Customer Portal as server actions, a
signature-verified webhook, and one sync function as the only writer of
subscription state. Plans, prices, and credit amounts live in
[src/config/plans.ts](src/config/plans.ts) and nowhere else.


- **Credits ledger** — append-only `credit_transactions` with UNIQUE
idempotency keys. Grants on `invoice.paid` (`grant_{invoiceId}`), top-ups
on checkout (`topup_{sessionId}`), spends as one conditional UPDATE (the
race guard), refunds as compensating rows. The database itself refuses
negative balances and zero-amount rows.
- **AI generation** — prompt → rate limit (10/min) → spend 1 credit →
AI SDK 6 `generateImage` → store (Vercel Blob, or `./.generated` in dev)
→ history grid. Provider failure refunds automatically. Swap models via
`AI_IMAGE_MODEL=provider/model`; add providers by implementing one
interface ([src/lib/ai/provider.ts](src/lib/ai/provider.ts)).
- **Design system** — "The Ledger, LOUD MODE": tokens and hard rules in
[DESIGN.md](DESIGN.md), light and dark, generated illustrations, an
interaction grammar with press physics. `/styleguide` (dev only) shows
every primitive in both themes.
## The AI-native part
This repo assumes an agent will extend it, and briefs the agent accordingly:
| File | What it does for the agent |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AGENTS.md](AGENTS.md) | The operating manual: commands, conventions, safety boundaries (NEVER / ASK FIRST), gotchas, definition of done. Works with Claude Code, Cursor, Codex, Copilot, Gemini CLI. |
| [CLAUDE.md](CLAUDE.md) | Imports AGENTS.md, adds plan-mode policy for money code and skill pointers. |
| [DESIGN.md](DESIGN.md) | Tokens plus hard rules, so generated UI stays on-brand. |
| `.claude/rules/` | Path-scoped invariants that load only when billing, database, or design files are touched. |
| `.claude/skills/` | `/add-feature`, `/add-ai-provider`, `/db-migration` — the common jobs, scripted the repo's way. |
| `.claude/hooks/` | Prettier after every edit; a Stop hook that blocks "done" until `tsc --noEmit` passes. |
| `.claude/agents/code-reviewer.md` | A read-only reviewer for auth/billing/ledger diffs. It found real money bugs during this repo's own build. |
| `specs/TEMPLATE.md` | Spec-first workflow — copy it, fill it, hand it to the agent. A filled example is included. |
With Claude Code: open the repo and the context loads itself; type
`/add-feature` to scaffold the repo way. With Cursor: `.cursor/rules/`
mirrors the same invariants. Everything defers to AGENTS.md, so there is
one source of truth to edit. Agent-assisted contributions are welcome —
run the repo's own gates and the code-reviewer agent before opening a PR
(see [CONTRIBUTING.md](CONTRIBUTING.md)).
## Architecture in one paragraph
Server Components by default; Server Actions for mutations; API routes only
for the Stripe webhook and the Better Auth handler. Zod validates every
boundary — forms, webhook payloads, and env
([src/lib/env.ts](src/lib/env.ts), the only place `process.env` is read).
Money is integer cents, credits are integers, and two modules own the
dangerous writes: [src/lib/credits/](src/lib/credits/) is the only code
that touches credit tables, and `syncStripeDataToDb` in
[src/lib/billing/sync.ts](src/lib/billing/sync.ts) is the only writer of
subscription state — webhooks are triggers, never sources of truth.
## Testing
```bash
pnpm test # Vitest — needs Postgres: docker compose up -d
pnpm test:e2e # Playwright — boots its own dev server on :3100
```
94 unit/integration tests: the full ledger behavioral suite against real
Postgres (double-spend race, exact-boundary spends, idempotent replays,
refunds, key-collision detection, invariant checks, DB CHECK probes),
webhook signature verification with real HMAC fixtures, sync derivation,
plans-config locks, env validation, email rendering. 12 e2e tests: signup
to dashboard, mock generation, the FAIL-refund path, the 0-credit block,
open-redirect guards, image-route authorization, billing plan cards from
the plans config.
The spend→refund loop is user-visible, not just tested: a failed
generation refunds its credit automatically and says so on the tile.

e2e runs against `next dev` deliberately — `AI_MOCK=true` is refused in
production builds, so a build+start e2e would hit a real provider. The
comment in [playwright.config.ts](playwright.config.ts) explains.
## Stripe, locally
1. Create three test-mode prices (Pro $9/mo, Ultra $29/mo, Top-up $5
one-time) in the [Stripe dashboard](https://dashboard.stripe.com/test/products)
or via the API, and put the `price_...` IDs in `.env`.
2. `pnpm stripe:listen` (Stripe CLI) — copy the printed `whsec_...` into
`.env`, restart `pnpm dev`.
3. Subscribe with card `4242 4242 4242 4242` → the webhook grants the
plan's credits, keyed by invoice ID. Resend the event from the Stripe
dashboard — the ledger's unique key makes the replay a no-op.
4. Renewals and cancellations can't wait a month: use
[test clocks](https://docs.stripe.com/billing/testing/test-clocks) to
advance time. Portal cancellations set `cancel_at` (not the legacy
boolean) — the sync handles both; don't "simplify" it.

## Deploy to production (Vercel + Neon)
The order matters — follow it top to bottom.
1. **Neon** — create a project and copy BOTH connection strings: the
**pooled** one (contains `-pooler`, for the running app) and the
**direct** one (for migrations).
2. **Vercel** — import the GitHub repo. Don't deploy yet.
3. **Blob store** — in the Vercel project: Storage → Create → Blob, with
**Access: Public**, and **tick "Add a read-write token env var"** — the
default flow skips it and leaves `BLOB_READ_WRITE_TOKEN` unset, which
silently sends generated images to the (nonexistent) local fallback.
4. **Environment variables** — everything from `.env.example`:
| Variable | Value |
| -------------------------------------- | ----------------------------------------- |
| `DATABASE_URL` | the **pooled** Neon URL (runtime traffic) |
| `BETTER_AUTH_SECRET` | `openssl rand -base64 32` |
| `BETTER_AUTH_URL` | the exact deployed URL — see step 9 |
| `STRIPE_SECRET_KEY` + 3 price IDs | from your Stripe dashboard |
| `STRIPE_WEBHOOK_SECRET` | placeholder for now — replaced in step 7 |
| `AI_GATEWAY_API_KEY`, `AI_IMAGE_MODEL` | AI Gateway; `AI_MOCK` stays UNSET |
| `RESEND_API_KEY`, `EMAIL_FROM` | verified Resend domain |
| `BLOB_READ_WRITE_TOKEN` | added by step 3's checkbox |
5. **Deploy** and note the real production domain Vercel assigns — it may
suffix the project name (e.g. `-six`).
6. **Migrate once**, locally, with the **direct** URL (the pooler rejects
some DDL): `DATABASE_URL="<direct Neon URL>" pnpm db:migrate`
7. **Stripe webhook** — create the endpoint for the REAL deployed domain:
`https://<real-domain>/api/stripe/webhook`, events `invoice.paid`,
`checkout.session.completed`, `customer.subscription.updated`,
`customer.subscription.deleted` — then copy its `whsec_...` into the
Vercel env, replacing the placeholder.
8. **Redeploy** — env changes never apply to a running deployment.
9. **Pin the domain** — set `BETTER_AUTH_URL` (env) and `siteConfig.url`
([src/config/site.ts](src/config/site.ts)) to the exact production URL
from step 5, push, and redeploy if either changed.
### Common deploy errors
| Error | Cause | Fix |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `Invalid origin: ...` on signup/login | `BETTER_AUTH_URL` doesn't match the actual domain — Vercel may have suffixed the project name | Set the exact URL in the env, redeploy |
| `Free tier users do not have access to this model` | The AI Gateway key has no paid credits — the key's quota is a spending cap, not a balance | Add credits to the gateway account, or bring your own provider key |
| Signup 500 / `relation "users" does not exist` | Migrations never ran against the production database | `DATABASE_URL="<direct Neon URL>" pnpm db:migrate` |
| Subscribed but no credits arrived | Webhook endpoint points at the wrong domain, stale `whsec_`, or the env changed without a redeploy | Recheck step 7's domain, replace the secret, redeploy |
Every env change requires a redeploy — Vercel bakes env at build time.
## FAQ
**Is this production-ready?** The billing and ledger core is tested to a
standard most products never reach (races, replays, invariants, adversarial
webhooks). The legal pages are placeholders and the product on top is
yours to build.
**Does it work with Claude Code / Cursor?** Yes — that's the point. The
repo carries its own agent context (AGENTS.md, CLAUDE.md, path-scoped
rules, skills, hooks); Cursor reads the mirrored `.cursor/rules/`. Open
the repo and the agent is briefed.
**How does the credits system work?** Every credit movement is an
append-only row in `credit_transactions` with a unique idempotency key,
so webhook replays can't double-grant. Spends are one conditional UPDATE
that refuses to go below zero, and the cached balance is enforced equal
to `SUM(amount)` by tests and a DB CHECK.
**Can I swap gpt-image for another model?** One env string:
`AI_IMAGE_MODEL=provider/model` — no code changes.
**Why Better Auth instead of NextAuth/Clerk?** Sessions and users live in
YOUR Postgres next to the ledger, so account deletion, credit grants, and
webhooks are one transaction-safe world. No per-user vendor pricing on a
free starter.
**Is this a free alternative to ShipFast or Makerkit?** It overlaps where
every SaaS starter overlaps — auth, Stripe, landing page — but the focus
is different: a tested credits ledger, an AI generation loop, and agent
context files, free and MIT. The paid kits are broader (teams, i18n,
admin); the Pro version covers that ground.
**Why is generation mocked by default?** So a fresh clone works offline and
free. Set `AI_GATEWAY_API_KEY` and `AI_MOCK=false` for real images; in mock
mode, a prompt containing `FAIL` demos the refund path.
**Can I swap Postgres providers?** Anything with a `postgres://` URL —
Neon, Supabase, RDS, the bundled Docker.
**Where do I start extending?** Copy `specs/TEMPLATE.md`, write ten lines,
and hand it to your agent with `/add-feature`.
## Free vs Pro
| Capability | Free — this repo | [Pro — nikandr.com](https://nikandr.com) |
| ----------------------------------------- | ---------------- | ---------------------------------------- |
| Auth, subscriptions, credits ledger | full | + rollover, meters, packs |
| AI generation | 1 image provider | image + video + audio, 7 providers |
| Async job pipeline, webhooks, auto-refund | — | Inngest, durable |
| Gallery + R2 storage, teams, admin | — | included |
| MCP server + extended agent skills | core set | full suite |
The free repo is complete — nothing above is crippled. Pro is what comes
after product-market fit.
## Author
Built by **Nikandr Surkov** — [nikandr.com](https://nikandr.com). If this
repo saved you time,
[star it](https://github.com/nikandr-surkov/ai-saas-starter/stargazers) —
stars are how other builders find it.
## License
MIT — see [LICENSE](LICENSE).
Explore similar templates
Compare previews and descriptions within the same stack and category.

Next.js SaaS Starter
The official Next.js SaaS starter template, integrating email/password authentication, Stripe Checkout subscriptions, a dashboard with user/team CRUD, basic Owner/Member RBAC, and activity logging.
Next.js · SaaS

Next.js Commerce
Vercel's officially maintained Next.js App Router ecommerce starter with deep Shopify integration, offering a complete product catalog, cart, and checkout flow. Core logic is modular for swapping backends, and community provider versions exist for BigCommerce, Medusa, and Saleor.
Next.js · E-commerce

Next-js-Boilerplate
A developer-first Next.js 16 starter with Tailwind CSS 4 and TypeScript, supporting both App Router and Page Router.
Next.js · Starter

tailwind-nextjs-starter-blog
A Next.js and Tailwind CSS blog starter template using Contentlayer for Markdown/MDX, with built-in SEO, code highlighting, and tags. It targets personal technical blogs and migration from Jekyll/Hugo to React, and supports one-click Vercel deployment.
Next.js · Blog

next-forge
next-forge is a Turborepo-based Next.js template maintained by Vercel, positioned as a starting point for SaaS products.
Next.js · Starter

SaaS-Boilerplate
SaaS-Boilerplate is an open-source SaaS starter template built with Next.js App Router, React 19, TypeScript, Tailwind CSS, and Shadcn UI.
Next.js · SaaS
