Build a SaaS App
From zero to deployed SaaS with auth, payments, and email
What You'll Build
A fully functional SaaS app with user authentication, subscription payments, transactional email, and production deployment.
- User signup & login with Supabase Auth
- Stripe subscription billing with webhooks
- Transactional emails via Resend
- Deployed to Vercel with CI/CD
Prerequisites
- Node.js 18+ installed
- A code editor (Cursor or VS Code)
- A GitHub account
- Basic React and JavaScript knowledge
Architecture
Next.js handles the frontend and API routes. Supabase provides the Postgres database and user authentication. Stripe processes subscription payments via webhooks that hit your Next.js API routes. Resend sends transactional emails triggered by server-side events. Vercel deploys everything automatically on git push.
Scaffold the Next.js project
~5 minCreate a new Next.js app with TypeScript, Tailwind CSS, and the App Router.
- Run the create command with TypeScript and Tailwind enabled
- Navigate into the project directory
- Start the dev server and confirm it loads at localhost:3000
npx create-next-app@latest my-saas --typescript --tailwind --eslint --app --src-dir
cd my-saas
npm run dev
"dev": "next dev --turbo" to your package.json scripts for faster development builds with Turbopack.Set up Supabase for database and auth
~15 minCreate a Supabase project, install the client libraries, and configure authentication.
- Go to supabase.com and create a new project
- Install the Supabase packages:
@supabase/supabase-jsand@supabase/ssr - Copy your project URL and anon key from Settings → API
- Create a
.env.localfile with your credentials - Create a Supabase client helper for browser and server usage
- Enable email/password auth in Authentication → Providers
npm install @supabase/supabase-js @supabase/ssr
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL! process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Build login and signup pages
~20 minCreate signup, login, and auth callback routes using Supabase Auth with server-side validation.
- Create a signup page at
/app/signup/page.tsxwith email and password fields - Create a login page at
/app/login/page.tsx - Create an auth callback route at
/app/auth/callback/route.tsfor OAuth and email confirmation - Add middleware to protect authenticated routes
- Create a dashboard page at
/app/dashboard/page.tsxthat requires login
import { createServerClient } from '@supabase/ssr'
import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const code = searchParams.get('code')
if (code) {
const cookieStore = cookies()
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL! process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! { cookies: { /* cookie handlers */ } }
)
await supabase.auth.exchangeCodeForSession(code)
}
return NextResponse.redirect(new URL('/dashboard', request.url))
}
Add Stripe subscription billing
~30 minInstall Stripe, create products and prices in the dashboard, and build a checkout flow with webhooks.
- Install the Stripe SDK:
npm install stripe - Create a Stripe account and grab your test API keys
- Add Stripe keys to
.env.local - Create products and prices in the Stripe Dashboard (e.g. Free, Pro, Team plans)
- Build an API route at
/api/checkout/route.tsthat creates a Checkout Session - Build a webhook handler at
/api/webhooks/stripe/route.tsto process subscription events - Sync subscription status to your Supabase
profilestable
npm install stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
import Stripe from 'stripe'
import { NextResponse } from 'next/server'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export async function POST(req: Request) {
const { priceId, userId } = await req.json()
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_URL}/dashboard?success=true`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
metadata: { userId }
})
return NextResponse.json({ url: session.url })
}
stripe listen --forward-to localhost:3000/api/webhooks/stripe to test webhooks locally.Set up transactional email with Resend
~10 minConfigure Resend to send welcome emails, payment receipts, and other transactional messages.
- Sign up at resend.com and create an API key
- Install the Resend SDK:
npm install resend - Add your API key to
.env.local - Create a reusable email utility at
src/lib/email.ts - Trigger a welcome email from your auth callback when a user signs up
npm install resend
import { Resend } from 'resend'
const resend = new Resend(process.env.RESEND_API_KEY)
export async function sendWelcomeEmail(email: string, name: string) {
await resend.emails.send({
from: 'Your SaaS <hello@yourdomain.com>',
to: email,
subject: `Welcome to the app, ${name}!`,
html: `<h1>Welcome aboard!</h1><p>Your account is ready.</p>`
})
}
Deploy to Vercel
~10 minPush to GitHub and deploy your SaaS to production with environment variables and CI/CD.
- Push your project to a GitHub repository
- Go to vercel.com and import your repository
- Add all your environment variables (Supabase URL/key, Stripe keys, Resend key)
- Deploy - Vercel auto-detects Next.js and configures everything
- Set up your Stripe webhook endpoint to point to your production URL
- Test the full flow: signup → login → subscribe → receive email
git init
git add .
git commit -m "Initial SaaS app"
git remote add origin https://github.com/you/my-saas.git
git push -u origin main
🎉 You're Done!
A fully functional SaaS app with user authentication, subscription payments, transactional email, and production deployment.
Want this built for you?
Get a step-by-step checklist, setup order, and the exact config for every tool in this guide. Or let me build it for you.
Get the checklist → Want this built for you?