Next.jsReactSaaSStarter

nextjs-saas-starter — Next.js SaaS Template

By mailtrap

A Next.js SaaS starter maintained by Mailtrap, using Mailtrap as the email layer and integrating Supabase authentication with Stripe subscription billing, intended for learning and personal projects.

Explore the design

Compare the page layouts and mobile experience. Open any screenshot for a closer look.

3 previews
Desktop homepage1 / 3
Desktop captureTop of page

Actual screenshot captured by the server browser.

All pages & views 3

Screenshots show visual appearance; interactive behavior may differ.

Recorded 2026-10-07View source

What stands out

A quick read of the recorded project description.

01

Maintained by Mailtrap, with the email layer directly integrated with Mailtrap's sending, templates, and webhooks

02

Integrates Supabase authentication and Postgres, with local Docker startup and migration scripts

03

Integrates Stripe subscription billing, including Checkout upgrades and changePlan() downgrade handling

04

Provides an /admin/emails page for viewing email events, with access controlled by ADMIN_EMAILS

05

Includes local webhook forwarding and testing scripts for Stripe and Mailtrap, without needing ngrok

06

Uses the MIT license, allowing free use, modification, commercial use, and distribution of this version of the code

Template Details

This is a blank-slate Next.js SaaS starter maintained by Mailtrap. It pre-wires three common infrastructure pieces: Mailtrap for the email layer, Supabase for authentication and the database, and Stripe for subscriptions and payments. The repository includes scripts needed for local development, such as starting Supabase Auth and Postgres via Docker, applying database migrations, generating .env.local, and providing local webhook forwarding and testing methods for Stripe and Mailtrap.

Email flows fall into two categories: Supabase's Send Email Hook hands authentication emails such as magic links, password resets, and email changes to Mailtrap for delivery; application events (welcome emails, team invitations, billing-related notifications) are sent through sendEmail() in src/lib/mailtrap. For billing, upgrades go through Stripe Checkout, while downgrades use changePlan() to cancel or update an existing subscription. The project also includes an /admin/emails page, accessible with emails listed in ADMIN_EMAILS, for viewing email events.

The author states clearly in the README that this starter is aimed at learners, indie developers, and junior developers, and is not a production-grade multi-tenant SaaS. Before use, you need Node.js, pnpm, Docker Desktop, the Stripe CLI, and a Mailtrap account, and you must fill in your own Supabase, Stripe, and Mailtrap keys plus 8 email template UUIDs. By default, local development delivers emails to Mailtrap's Email Testing inbox rather than real recipient inboxes.

Next.jsSaaSStarter

Is it right for your project?

Use Cases

  • Learning how authentication, subscription billing, and transactional email fit together into a SaaS skeleton in Next.js
  • Quickly building a product prototype with login, paid plans, and email notifications as an individual or indie developer
  • Projects that need Supabase Auth authentication emails to be sent through Mailtrap instead
  • Validating billing functionality starting from Stripe Checkout and subscription change logic

Suitable For

  • Learners and junior developers understanding how basic SaaS modules are wired together
  • Indie developers building personal projects or early prototypes, rather than deploying directly to production
  • Teams needing an example that combines the Mailtrap email layer with Supabase and Stripe

Getting started & customization

Use these recorded setup notes alongside the repository instructions for your chosen version.

  1. 1

    Requires Node.js 20+, pnpm 10+, Docker Desktop, the Stripe CLI, and a Mailtrap account

  2. 2

    First run pnpm db:setup to start local Supabase and generate .env.local, then fill in variables such as Mailtrap, Stripe, and ADMIN_EMAILS

  3. 3

    NEXT_PUBLIC_APP_URL determines the development port, the Supabase callback URL, and the Send Email Hook URL at the same time; after changing the port, run pnpm sync:env and restart the database

  4. 4

    For local billing sync, run stripe listen in a separate terminal to forward to /api/webhooks/stripe, and write the signing secret into STRIPE_WEBHOOK_SECRET

  5. 5

    During local development, it is recommended to keep MAILTRAP_SANDBOX=true so emails go to the Mailtrap Email Testing inbox; change it to false before deployment

Read repository instructions

License & source material

Usage conditions & limitations

Free to use · keep license notice

This listing covers the free version in the public repository under the MIT license; the free scope is this version of the code and does not mean external services or third-party assets are free.

Must comply with when using

  • Free use, modification, commercial use, and distribution of this version of the code are allowed.
  • 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

  • Demo images, fonts, icons, and other third-party assets must be checked against 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 incur separate charges.
  • The project is positioned for learning and prototyping; the author explicitly states it is not a production-grade multi-tenant SaaS and should not be used directly in production.
  • Using the email features requires registering a Mailtrap account and providing an API token, an Email Testing inbox, and hosted templates.
  • Debugging local billing webhooks requires installing the Stripe CLI and configuring Stripe keys and price IDs.
  • Starting Supabase Auth and Postgres locally depends on Docker Desktop.
  • By default, local development emails only go to the Mailtrap test inbox rather than real mailboxes; before deploying to production, MAILTRAP_SANDBOX must be set to false.
  • You must fill in your own Mailtrap API token, sandbox inbox ID, sender address, and 8 email template UUIDs.
  • You must configure your own Stripe keys, webhook signing secret, and the Pro and Team price IDs.
  • Accessing the /admin/emails admin page requires putting your own email in ADMIN_EMAILS.
  • If not using Docker, you need to create a cloud project on supabase.com, run the migration SQL, and configure API keys and callback URLs.
View Original Text Basis

Permission is hereby granted, free of charge

Original License Text

For learners, indie hackers, and juniors — not production-grade multi-tenant SaaS.

Original README

[Mailtrap](https://mailtrap.io) account (API token + Email Testing inbox + hosted templates)

Original README

- [Stripe CLI](https://stripe.com/docs/stripe-cli) (for local billing webhooks)

Original README

- [Docker Desktop](https://docs.docker.com/get-docker/) (for local Supabase)

Original README

Emails appear in your **Mailtrap Email Testing inbox**, not the recipient's real mailbox. Set `MAILTRAP_SANDBOX=false` before production deploy.

Original README

1. **Mailtrap** — API token, sandbox inbox ID, from address, 8 template UUIDs

Original README

2. **Stripe** — secret key, webhook secret (from Stripe CLI below), Pro + Team price IDs

Original README

3. **Admin** — your email in `ADMIN_EMAILS` (for `/admin/emails`)

Original README

Create a project at [supabase.com](https://supabase.com), run SQL from `supabase/migrations/`, copy API keys into `.env.local`, and configure:

Original README
https://github.com/mailtrap/nextjs-saas-starter/blob/main/LICENSEhttps://github.com/mailtrap/nextjs-saas-starter/blob/main/README.md

Compiled by DeepSeek based on repository license and README ·2026-10-07. 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 · 88 / 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-09-29
Screenshot last checked
2026-10-07

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.

Review declaration: [email protected] · 2026-10-08

Inspect the recorded source material

SHA-256: aa788be0ee61e95dcdda2735114b5d76555c9336ca7aca6b6de98020dd56cc63

2026-10-07T19:06:08.818Z

Source file / repository
# nextjs-saas-starter

Blank-slate Next.js SaaS scaffolding with **Mailtrap** as the email layer, **Supabase** auth, and **Stripe** billing.

For learners, indie hackers, and juniors — not production-grade multi-tenant SaaS.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmailtrap%2Fnextjs-saas-starter&env=NEXT_PUBLIC_APP_URL,NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY,SUPABASE_SERVICE_ROLE_KEY,DATABASE_URL,SEND_EMAIL_HOOK_SECRET,STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,STRIPE_PRICE_PRO,STRIPE_PRICE_TEAM,MAILTRAP_API_TOKEN,MAILTRAP_WEBHOOK_SECRET,MAILTRAP_FROM_EMAIL,MAILTRAP_FROM_NAME,MAILTRAP_TPL_WELCOME,MAILTRAP_TPL_MAGIC_LINK,MAILTRAP_TPL_RESET_PASSWORD,MAILTRAP_TPL_TEAM_INVITE,MAILTRAP_TPL_PAYMENT_RECEIPT,MAILTRAP_TPL_DUNNING,MAILTRAP_TPL_CANCELLATION,MAILTRAP_TPL_PLAN_CHANGE,ADMIN_EMAILS&project-name=nextjs-saas-starter)

## Prerequisites

- [Node.js](https://nodejs.org) 20+
- [pnpm](https://pnpm.io) 10+
- [Docker Desktop](https://docs.docker.com/get-docker/) (for local Supabase)
- [Stripe CLI](https://stripe.com/docs/stripe-cli) (for local billing webhooks)
- [Mailtrap](https://mailtrap.io) account (API token + Email Testing inbox + hosted templates)

## Quick start (local)

```bash
git clone https://github.com/mailtrap/nextjs-saas-starter.git
cd nextjs-saas-starter
pnpm install
pnpm db:setup          # Docker: Supabase Auth + Postgres + schema → writes .env.local
```

Copy remaining values from [`.env.example`](.env.example) into `.env.local`:

1. **Mailtrap** — API token, sandbox inbox ID, from address, 8 template UUIDs
2. **Stripe** — secret key, webhook secret (from Stripe CLI below), Pro + Team price IDs
3. **Admin** — your email in `ADMIN_EMAILS` (for `/admin/emails`)

Optional Stripe test products/prices:

```bash
stripe fixtures stripe-fixtures.json --api-key "$STRIPE_SECRET_KEY"
```

Start the app (port comes from `NEXT_PUBLIC_APP_URL`):

```bash
pnpm dev
```

Open the URL in `.env.local` (default `http://127.0.0.1:3000`).

### Port / URL configuration

`NEXT_PUBLIC_APP_URL` is the single source of truth for:

- Next.js dev port (`pnpm dev`)
- Supabase `site_url` and auth redirects
- Send Email Hook URI (Docker → host app)

If port 3000 is taken, set e.g. `NEXT_PUBLIC_APP_URL=http://127.0.0.1:3001`, then:

```bash
pnpm sync:env
pnpm db:stop && pnpm db:start
pnpm dev
```

### What `pnpm db:setup` does

1. Starts **only** Supabase Auth + Postgres (not Storage, Studio, Realtime, etc.)
2. Applies [`supabase/migrations/`](supabase/migrations/) (source of truth for schema)
3. Writes Supabase credentials into `.env.local`
4. Syncs auth hook URL and redirect URLs from `NEXT_PUBLIC_APP_URL`

**Stop Docker:** `pnpm db:stop` · **Reset database:** `pnpm db:reset` · **Restart:** `pnpm db:start`

### Cloud Supabase instead of Docker

Create a project at [supabase.com](https://supabase.com), run SQL from `supabase/migrations/`, copy API keys into `.env.local`, and configure:

- Auth → URL → your `NEXT_PUBLIC_APP_URL`
- Auth → Hooks → Send Email → `https://YOUR_APP/api/auth/send-email`

## Local webhooks

### Stripe (required for billing sync)

In a second terminal (use the port from `NEXT_PUBLIC_APP_URL`):

```bash
stripe listen --forward-to localhost:3001/api/webhooks/stripe --api-key "$STRIPE_SECRET_KEY"
```

Copy the webhook signing secret into `STRIPE_WEBHOOK_SECRET` in `.env.local`.

### Mailtrap (optional locally — no ngrok needed)

Set `MAILTRAP_WEBHOOK_SECRET` in `.env.local`, then simulate an event:

```bash
pnpm webhook:test:mailtrap
```

Refresh `/admin/emails` to see the test event. In production, point Mailtrap webhooks at `https://YOUR_APP/api/webhooks/mailtrap`.

## Env vars

| Group | What you need |
|-------|----------------|
| **App** | `NEXT_PUBLIC_APP_URL` — dev port, redirects, Supabase hook (`pnpm sync:env` after changes) |
| **Supabase** | 4 vars — auto-filled by `pnpm db:setup` locally |
| **Stripe** | `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `STRIPE_PRICE_PRO`, `STRIPE_PRICE_TEAM` |
| **Mailtrap** | API token, sandbox flag + inbox ID, from address, 8 template UUIDs, webhook secret |
| **Auth hook** | `SEND_EMAIL_HOOK_SECRET` — auto-filled locally |
| **Admin** | `ADMIN_EMAILS` — comma-separated emails for `/admin/emails` |

Full list: [`.env.example`](.env.example)

### Mailtrap sandbox (recommended for local dev)

```bash
MAILTRAP_SANDBOX=true
MAILTRAP_ACCOUNT_ID=12345           # optional, silences SDK warning
MAILTRAP_TEST_INBOX_ID=123456       # Email Testing → inbox settings
MAILTRAP_WEBHOOK_SECRET=your-secret # local: any string; match in Mailtrap dashboard for prod
```

Emails appear in your **Mailtrap Email Testing inbox**, not the recipient's real mailbox. Set `MAILTRAP_SANDBOX=false` before production deploy.

## Architecture

```
src/app/          → routes (marketing, auth, dashboard, API webhooks)
src/actions/      → Server Actions (auth, billing, org, settings)
src/lib/mailtrap  → sendEmail(), webhook signature verify
src/config/emails → typed template UUID map
src/db/           → Drizzle schema (profiles, orgs, subscriptions, email events)
```

**Email flows:** Supabase Send Email Hook → Mailtrap (magic link, password reset, email change). App events → `sendEmail()` (welcome, invites, billing).

**Billing:** Stripe Checkout for upgrades; downgrades cancel or update the existing subscription via `changePlan()`.

## Where to add your product logic

1. Create `src/features/your-feature/` — see [`src/features/README.md`](src/features/README.md)
2. Add a route under `src/app/dashboard/your-feature/page.tsx` (or another app route)
3. Call `sendEmail()` from `@/lib/mailtrap` for new transactional emails

## Scripts

```bash
pnpm db:setup              # first-time local setup (Docker + migrations + .env.local)
pnpm db:start              # start Supabase + reset + sync env
pnpm db:stop               # stop Docker Supabase
pnpm db:reset              # re-apply supabase/migrations
pnpm sync:env              # sync Supabase auth URLs from NEXT_PUBLIC_APP_URL
pnpm dev                   # Next.js dev server (port from NEXT_PUBLIC_APP_URL)
pnpm build && pnpm start   # production build
pnpm lint
pnpm typecheck
pnpm test                  # unit tests (vitest)
pnpm test:e2e              # Playwright
pnpm webhook:test:mailtrap # local Mailtrap webhook test (no ngrok)
pnpm lighthouse            # Lighthouse CI
```

Schema changes: edit `supabase/migrations/`, then `pnpm db:reset`. The `drizzle/` folder mirrors schema for Drizzle ORM queries; `db:generate` / `db:push` are optional and not used by default setup.

## Post-deploy checklist

1. Run `supabase/migrations/` SQL on production Postgres (or link hosted Supabase)
2. Set all env vars from `.env.example`
3. Stripe → Webhooks → `https://YOUR_APP/api/webhooks/stripe`
4. Mailtrap → Webhooks → `https://YOUR_APP/api/webhooks/mailtrap`
5. Supabase → Auth → Hooks → Send Email → `https://YOUR_APP/api/auth/send-email`
6. Paste Mailtrap template UUIDs and verify sending domain
7. Set `ADMIN_EMAILS` for admin access

## License

MIT
Report a correction

Explore similar templates

Compare previews and descriptions within the same stack and category.