Next.jsReactAdmin dashboardSaaSStarter

saas-starter-nextjs — Next.js Admin dashboard Template

By bxdr-glitch

A SaaS starter template built on the Next.js App Router, integrating Supabase authentication with Postgres RLS, Stripe subscription billing, a dashboard, and marketing pages, under the MIT license.

Explore the design

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

2 previews
Desktop homepage1 / 2
Desktop captureTop of page

Actual screenshot captured by the server browser.

All pages & views 2

Screenshots show visual appearance; interactive behavior may differ.

Recorded 2026-10-02View source

What stands out

A quick read of the recorded project description.

01

Integrates Supabase Auth with magic links, Google and GitHub OAuth, using cookie sessions and Proxy refresh

02

Integrates Stripe Checkout and Customer Portal, providing a pricing page, subscription status, cancellation/upgrade, and invoices

03

Stripe webhook runs as a Supabase Edge Function, including subscription tables and webhook idempotency logs

04

Provides a protected dashboard with a sidebar shell, account settings, and billing management

05

Marketing pages include a hero, pricing, testimonials, and FAQ

06

Uses Resend to send welcome emails and invoice.paid receipt emails

Template Details

Paperstack is a Next.js SaaS starter template that includes a marketing site, authentication, Stripe subscription billing, and a protected dashboard. The stack is Next.js App Router, Supabase Auth + Postgres RLS, Stripe Checkout + Customer Portal, Resend email, Tailwind CSS, and shadcn/ui. Authentication supports magic links and Google and GitHub OAuth, uses cookie sessions, and refreshes via Proxy. Billing provides a pricing page, Stripe Checkout, webhook synchronization, subscription status, a cancellation/upgrade portal, and invoices; the webhook runs as a Supabase Edge Function and handles events such as checkout.session.completed, subscription creation/update/deletion, invoice.payment_failed, and invoice.paid. The dashboard includes a sidebar shell, account settings, and billing management; the marketing pages include a hero, pricing, testimonials, and FAQ. For email, a welcome email is sent after the first login, and a receipt email is sent after invoice.paid. The project also reuses patterns from the stripe-supabase-webhooks and supabase-rls-patterns repositories, including subscription tables, webhook idempotency logs, RLS policies based on auth.uid(), and SECURITY DEFINER helper functions.

Next.jsDashboardSaaSStarter

Is it right for your project?

Use Cases

  • Quickly building a SaaS product prototype with authentication and subscription billing
  • Learning how to integrate the Next.js App Router with Supabase RLS and Stripe webhooks
  • Serving as a starting point for a backend project that needs marketing pages, login, and a dashboard
  • Testing the complete subscription flow locally with the Supabase CLI and Stripe CLI

Suitable For

  • SaaS project developers who need a Next.js + Supabase + Stripe combination
  • Backend developers who want to reuse RLS policies and webhook idempotency patterns
  • Independent developers or small teams who need authentication, billing, and dashboard infrastructure quickly

Getting started & customization

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

  1. 1

    Requires Node.js 20+, npm, the Supabase CLI, and the Stripe CLI; a Stripe test-mode account is sufficient

  2. 2

    Copy .env.example to .env.local and fill in variables such as Supabase, Stripe, Resend, and the site URL

  3. 3

    Run npx supabase start and npx supabase db reset locally, then obtain local keys from npx supabase status

  4. 4

    To test webhooks locally, use supabase functions serve and stripe listen to forward events, and write the CLI signing secret to STRIPE_WEBHOOK_SECRET

  5. 5

    For OAuth, configure Google/GitHub credentials in Supabase, with the callback URL pointing to Supabase's /auth/v1/callback

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 the code of that version and does not mean that external services or third-party assets are free.

Must comply with when using

  • You may use, modify, commercialize, and distribute the code of this version for free.
  • When distributing copies or substantial portions of the code, retain the original author's copyright notice and the complete 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 the billing features requires registering a Stripe account (test mode is sufficient) and creating two recurring subscription prices (Starter and Growth), then filling the price IDs into environment variables.
  • Actually sending welcome emails and receipt emails requires a Resend account and API key; local UI development alone may skip this configuration.
  • Enabling Google/GitHub login requires creating OAuth applications in Google Cloud and GitHub yourself, and configuring credentials and callback URLs in Supabase.
  • Local running and database migrations depend on the Supabase CLI and Supabase services (local or hosted), and require configuring a Supabase project and keys.
  • Testing Stripe webhooks locally requires installing the Stripe CLI and forwarding events, and writing the CLI signing secret to STRIPE_WEBHOOK_SECRET.
  • Sending email in production requires verifying your own domain in Resend and updating the sender address.
  • The project materials mention optional paid versions or features; this listing covers only the public free code and does not include paid upgrades.
  • Demo images, fonts, icons, and other third-party assets must be checked against their respective licenses; the code's MIT license alone cannot be used to judge them.
  • External services such as domains, hosting, databases, payments, or AI may incur separate charges.
View Original Text Basis

Permission is hereby granted, free of charge

Original License Text

A Stripe account (test mode is fine)

Original README

A Resend account (optional for local UI work, required for real email)

Original README

Create OAuth apps in Google Cloud and GitHub.

Original README

[Supabase CLI](https://supabase.com/docs/guides/cli)

Original README

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

Original README

For production, verify your domain and update `RESEND_FROM_EMAIL`.

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

Compiled by DeepSeek based on repository license and README ·2026-10-02. 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
Admin dashboard · 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-19
Screenshot last checked
2026-10-02

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: 7f76ba8723e1435a967b2d2555662bcbf20e05105683aa7591b595b9c28f92a6

2026-10-02T18:23:58.866Z

Source file / repository
# Paperstack

A Next.js SaaS starter with auth, billing, a dashboard, and a marketing site. It is the web counterpart to a mobile Expo boilerplate.

**Stack:** Next.js App Router, Supabase Auth + Postgres RLS, Stripe Checkout + Customer Portal, Resend email, Tailwind CSS, and shadcn/ui.

## What you get

- **Auth:** Magic link plus Google and GitHub OAuth, cookie sessions, and Proxy-based refresh
- **Billing:** Pricing page, Stripe Checkout, webhook sync, subscription status, cancel/upgrade portal, invoices
- **Dashboard:** Sidebar shell, account settings, and billing management
- **Marketing:** Landing page with hero, pricing, testimonials, and FAQ
- **Email:** Welcome email after first sign-in, receipt email after `invoice.paid`

## Reused repositories

This starter reuses patterns from two sibling repos.

### `stripe-supabase-webhooks` 

Copied and adapted into this project:

| Source | Where it lives here |
| --- | --- |
| Subscriptions schema | [`supabase/migrations/202607190002_subscriptions.sql`](supabase/migrations/202607190002_subscriptions.sql) |
| Webhook idempotency log | [`supabase/migrations/202607190003_webhook_events.sql`](supabase/migrations/202607190003_webhook_events.sql) |
| Edge Function webhook | [`supabase/functions/stripe-webhook`](supabase/functions/stripe-webhook) |
| Checkout helper idea | [`src/lib/stripe/checkout.ts`](src/lib/stripe/checkout.ts) (Node/Server Actions) |

The webhook still runs as a Supabase Edge Function. The Next.js app creates Checkout and Customer Portal sessions, then reads `subscriptions` through RLS.

### `supabase-rls-patterns` 

Adapted into runnable migrations:

| Pattern idea | Where it lives here |
| --- | --- |
| Owner-scoped rows (`auth.uid()`) | Profiles + subscriptions SELECT policies |
| Explicit table grants with RLS | Profiles and subscriptions migrations |
| `SECURITY DEFINER` helpers | `claim_welcome_email` / `release_welcome_email` |
| Service-role-only writes for billing | No client INSERT/UPDATE on `subscriptions` or `webhook_events` |

## Prerequisites

- Node.js 20+
- npm
- [Supabase CLI](https://supabase.com/docs/guides/cli)
- [Stripe CLI](https://docs.stripe.com/stripe-cli) for local webhook testing
- A Stripe account (test mode is fine)
- A Resend account (optional for local UI work, required for real email)

## Quick start

```bash
npm install
cp .env.example .env.local
```

Fill in the values described below, then:

```bash
npx supabase start
npx supabase db reset
npm run dev
```

Open [http://localhost:3000](http://localhost:3000).

Useful local Supabase URLs after `supabase start`:

- API: `http://127.0.0.1:54321`
- Studio: `http://127.0.0.1:54323`
- Inbucket (auth emails): `http://127.0.0.1:54324`

Copy the local anon/publishable and service role keys from `npx supabase status` into `.env.local`.

## Environment variables

See [`.env.example`](.env.example). The important ones:

| Variable | Used for |
| --- | --- |
| `NEXT_PUBLIC_SUPABASE_URL` | Browser + server Supabase client |
| `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` | Public Supabase key (anon key still works as an alias) |
| `SUPABASE_SERVICE_ROLE_KEY` | Edge Function secrets only, never expose to the browser |
| `STRIPE_SECRET_KEY` | Checkout and Customer Portal Server Actions |
| `STRIPE_WEBHOOK_SECRET` | Signature verification in the Edge Function |
| `STRIPE_PRICE_STARTER_MONTHLY` / `STRIPE_PRICE_GROWTH_MONTHLY` | Paid plan Checkout prices |
| `RESEND_API_KEY` / `RESEND_FROM_EMAIL` | Welcome + receipt email |
| `NEXT_PUBLIC_SITE_URL` | Auth redirects and Checkout return URLs |

## Auth setup

The app wiring for magic link, Google, and GitHub is already in place:

- Server Actions: [`src/actions/auth.ts`](src/actions/auth.ts)
- Callback + confirm handlers: [`src/app/auth/callback`](src/app/auth/callback), [`src/app/auth/confirm`](src/app/auth/confirm)
- Session refresh: [`src/proxy.ts`](src/proxy.ts)

Without Supabase keys in `.env.local`, the login page shows a setup banner and auth actions return a clear error. They will not crash.

### Magic link

Works as soon as local (or hosted) Supabase is configured.

1. Set `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`, and `NEXT_PUBLIC_SITE_URL`.
2. Confirm Site URL is `http://localhost:3000` and these redirects are allowed:
   - `http://localhost:3000/auth/callback`
   - `http://localhost:3000/auth/confirm`
3. Local emails land in Inbucket at `http://127.0.0.1:54324`.
4. This repo ships a magic-link email template that uses `/auth/confirm?token_hash=...`, so the link works even if the email client opens in a different browser context.

### Google / GitHub OAuth

Buttons are live in the UI. They need provider credentials in Supabase before they succeed.

1. Create OAuth apps in Google Cloud and GitHub.
2. Enable the providers in the Supabase dashboard (or Studio for local).
3. Set each provider callback URL to:

```text
https://<your-project-ref>.supabase.co/auth/v1/callback
```

For local Supabase:

```text
http://127.0.0.1:54321/auth/v1/callback
```

4. Keep the app redirect allow list pointed at `/auth/callback`.
5. After Google or GitHub approves the user, Supabase returns a PKCE `code` to `/auth/callback`, which exchanges it for a session cookie and sends the user to the dashboard.

## Stripe setup

1. Create two recurring products/prices in Stripe test mode (Starter and Growth).
2. Put the price IDs into `.env.local`.
3. In Stripe Customer Portal settings, enable plan changes and cancellation.
4. Keep the portal return URL pointing at your site (the app passes `/dashboard/billing`).

### Local webhook testing

Serve the Edge Function:

```bash
npx supabase functions serve stripe-webhook --env-file .env.local --no-verify-jwt
```

Forward Stripe events:

```bash
stripe listen --forward-to http://127.0.0.1:54321/functions/v1/stripe-webhook
```

Copy the CLI webhook signing secret into `STRIPE_WEBHOOK_SECRET`, then retry Checkout with a test card such as `4242 4242 4242 4242`.

Events handled:

- `checkout.session.completed`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`
- `invoice.payment_failed`
- `invoice.paid` (also sends the Resend receipt)

## Deploy the webhook

Set secrets, then deploy:

```bash
npx supabase secrets set STRIPE_SECRET_KEY=sk_live_or_test
npx supabase secrets set STRIPE_WEBHOOK_SECRET=whsec_...
npx supabase secrets set RESEND_API_KEY=re_...
npx supabase secrets set RESEND_FROM_EMAIL="Paperstack <[email protected]>"
npx supabase secrets set APP_NAME=Paperstack
npx supabase functions deploy stripe-webhook --no-verify-jwt
```

In the Stripe Dashboard, create an endpoint:

```text
https://<your-project-ref>.supabase.co/functions/v1/stripe-webhook
```

Subscribe it to the events listed above. Use the Dashboard signing secret for production, not the Stripe CLI secret.

## Resend setup

1. Create an API key in Resend.
2. For local development you can send from `[email protected]`.
3. For production, verify your domain and update `RESEND_FROM_EMAIL`.
4. Welcome email sends once after the first authenticated session.
5. Receipt email sends from the webhook on `invoice.paid`, with an idempotency key based on the invoice id.

## Project map

```text
src/
  app/
    (marketing)/     Landing + pricing
    (auth)/login     Magic link + OAuth
    auth/            PKCE callback + token confirm
    dashboard/       Protected shell, account, billing
  actions/           Server Actions for auth + billing
  components/        Marketing, dashboard, and UI primitives
  emails/            React Email welcome template
  lib/               Supabase, Stripe, plans, helpers
supabase/
  migrations/        Profiles, subscriptions, webhook log
  functions/         Stripe webhook Edge Function
```

## Scripts

```bash
npm run dev          # Next.js dev server
npm run build        # Production build
npm run start        # Serve the production build
npm run lint         # ESLint
npm run typecheck    # TypeScript
npm test             # Vitest unit tests
```

## Deploy the Next.js app

1. Push the repo to GitHub.
2. Import the project into Vercel (or your host of choice).
3. Add the same environment variables from `.env.example`.
4. Set `NEXT_PUBLIC_SITE_URL` to your production URL.
5. Update Supabase Auth Site URL + redirect allow list for production.
6. Point Stripe and Resend at production keys and domains.

## Troubleshooting

**Magic link opens but I am still logged out**  
Confirm `/auth/callback` and `/auth/confirm` are allowed redirects, and that Proxy is running (it lives in `src/proxy.ts`).

**Checkout succeeds but the dashboard still shows Free**  
Check Stripe CLI forwarding, the Edge Function logs, and the `subscriptions` / `webhook_events` tables. A failed event claim is deleted so Stripe can retry.

**OAuth returns an error**  
Provider callback must go to Supabase (`/auth/v1/callback`), not directly to Next.js. The app then finishes the PKCE exchange at `/auth/callback`.

**Emails are silent**  
Welcome email needs `RESEND_API_KEY` in the Next.js env. Receipt email needs the same secrets on the Edge Function.

**`supabase db reset` complains about seed**  
This project includes an empty `supabase/seed.sql` so resets stay quiet.

## License

MIT License. Copyright (c) 2026 Rami Badr. See [LICENSE](LICENSE).
Report a correction

Explore similar templates

Compare previews and descriptions within the same stack and category.