TL;DR: A SaaS (Software as a Service) app is a web app people pay a recurring subscription to use. Building one requires four things your AI coding tool can help you with: user accounts (authentication), a place to store data (database), a way to collect money (Stripe billing), and a way to make it live on the internet (deployment). This guide walks through each step with real prompts you can drop straight into Cursor or any AI coding tool.

What You're Actually Building

Before we touch any code, let's be clear about what a SaaS app actually is and what makes it different from a regular website.

A regular website shows information. A SaaS app does something — and it does it for specific users who pay for access. Think of tools like Notion, Loom, or Calendly. They all share the same four-layer structure:

Layer What It Does Tool We'll Use
Frontend The pages users see and click on Next.js (React)
Authentication Sign up, log in, stay logged in Clerk
Database Store user data, subscriptions, app content PostgreSQL (via Supabase)
Billing Collect subscription payments Stripe
Deployment Put it live on the internet Vercel

We'll build a simple but real example: a link-in-bio tool. Users sign up, add their social links and a short bio, and get a shareable page. Free users get 3 links; paid users get unlimited links and custom themes. This is simple enough to build in a weekend, complex enough to teach every layer of a real SaaS.

Step 0: Your AI Coding Setup

Before you write a single line of code, get your AI coding environment right. This guide assumes you're using Cursor — it's the AI editor most vibe coders use for projects this size. If you're using VS Code with Copilot, the prompts still work; the workflow is the same.

You'll also need accounts on:

  • GitHub — to store your code
  • Supabase — free PostgreSQL database hosting
  • Clerk — managed authentication (free tier is generous)
  • Stripe — payment processing (test mode is free)
  • Vercel — deployment (free hobby tier)

Prompt — Project Scaffolding

Create a new Next.js 14 project using the App Router.
Set it up with:
- TypeScript
- Tailwind CSS
- A /app folder structure
- A basic home page at / that says "Welcome to LinkDrop"
- A /dashboard page that's empty for now

Name the project "linkdrop". Show me the exact terminal
commands to run.

Cursor will give you the exact commands. Run them in your terminal. Once your app loads at localhost:3000, you're ready for Step 1.

Step 1: Authentication — Sign Up, Log In, Stay Logged In

Authentication is the system that knows who you are. When a user types their email and password and clicks "Sign In," authentication is what checks those credentials, creates a session, and keeps them logged in as they click around the app.

Building authentication from scratch is notoriously difficult to get right — there are security pitfalls that can take years of experience to recognize. That's why we're using Clerk, a service that handles all of it for you. You get sign-up forms, login pages, password resets, and session management out of the box.

Want to understand what authentication is doing under the hood? Read What Is Authentication? — it explains sessions, tokens, and why rolling your own auth is risky.

Prompt — Install and Configure Clerk

I'm building a Next.js 14 App Router project.
Add Clerk authentication with this setup:

1. Install the @clerk/nextjs package
2. Add ClerkProvider to my root layout.tsx
3. Create a middleware.ts at the project root that
   protects /dashboard and all routes under /dashboard/*
4. Add a sign-in button to the navbar that shows
   "Sign In" when logged out and the user's first name
   when logged in
5. Redirect users to /dashboard after they sign in

My Clerk publishable key is in .env.local as
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY.
Show me every file I need to create or modify.

After running this, your app will redirect any unauthenticated user who tries to visit /dashboard to a Clerk-hosted sign-in page. Once they sign in, they land on the dashboard. That's full authentication — in one prompt.

What "middleware" means here

Middleware runs before a page loads and can decide whether to allow access. It's the bouncer at the door. The middleware.ts file we added checks: "Is this user logged in?" If no, it redirects them to sign in. If yes, it lets them through. You don't need to add that check to every individual page — one middleware file covers everything.

Step 2: Database — Storing Your Users' Data

Every SaaS app needs a place to store information that persists — user profiles, their links, their subscription status. That's what a database is. We're using PostgreSQL, the most widely-used database for web apps. Supabase gives you a free hosted PostgreSQL database with a nice dashboard.

If you want to understand what PostgreSQL is and why it's a good choice, read What Is PostgreSQL?.

For our link-in-bio app, we need two database tables:

  • profiles — one row per user, storing their bio, username, and subscription status
  • links — one row per link, storing the title, URL, and which user it belongs to

Prompt — Database Schema and API Routes

I'm building a link-in-bio SaaS with Next.js 14 and
PostgreSQL via Supabase. I use Clerk for auth.

Create the following:

1. SQL to create two tables in Supabase:
   - profiles: id (uuid), clerk_user_id (text, unique),
     username (text, unique), bio (text),
     is_pro (boolean, default false),
     stripe_customer_id (text),
     created_at (timestamp)
   - links: id (uuid), profile_id (uuid references
     profiles.id), title (text), url (text),
     display_order (integer), created_at (timestamp)

2. A /app/api/profile/route.ts with:
   - GET: fetch the current user's profile + their links
   - POST: create a profile for a new user

3. A /app/api/links/route.ts with:
   - GET: return all links for the current user
   - POST: create a new link (validate URL format)
   - DELETE: delete a link by id

Use the Supabase JS client. The connection string is
in .env.local as DATABASE_URL.
Check Clerk's auth() to get the current user's ID
before any database operation.

This prompt gives you working REST API routes that talk to your database. The key detail in the prompt: "Check Clerk's auth() before any database operation." This is the instruction that ties authentication to data access — ensuring users can only see and modify their own data.

Always check this

When your AI generates database routes, verify that every route that reads or writes data first checks who the logged-in user is. If a route fetches data without that check, any user could access any other user's data. This is the most common security mistake in AI-generated API code.

Step 3: The Dashboard — Where Users Manage Their Stuff

Now that you have auth and a database, build the UI where users actually do things. This is where React comes in — Next.js is built on React, so your pages are made of components (reusable UI pieces).

Prompt — Dashboard UI

Build the /dashboard page for my link-in-bio SaaS.
The dashboard should:

1. Show the user's current links as a list with
   a delete button next to each one
2. Show a form to add a new link (title + URL fields,
   submit button)
3. Show a "Upgrade to Pro" banner if is_pro is false.
   Free users are limited to 3 links — if they have 3
   already, disable the add form and show
   "Upgrade to Pro to add more links"
4. Fetch data from /api/profile on load
5. After adding or deleting a link, refresh the list
6. Show a loading state while fetching

Use Tailwind CSS. Keep it clean and functional —
no fancy animations needed.
Use TypeScript with proper interfaces for Profile
and Link types.

Notice how the prompt specifies the business rule (free users get 3 links) in plain English. AI tools are good at turning rules like this into real UI logic — but you have to tell them the rule. The AI doesn't know your pricing model; you do.

Step 4: Billing — Getting Paid with Stripe

This is the step most people are most nervous about. Money is involved. But Stripe is genuinely well-designed for developers, and with AI help, the integration is more approachable than it looks.

Here's what Stripe actually does in your app:

  1. User clicks "Upgrade to Pro"
  2. Your app creates a Checkout Session — a Stripe-hosted payment page
  3. User fills in their card details on Stripe's page (not your app — you never touch card numbers)
  4. Stripe charges the card and sends a webhook — an automatic notification — to your app
  5. Your app receives the webhook, confirms the payment, and flips is_pro to true in your database

For a deeper look at how Stripe integrations work, see What Is a Stripe Integration?.

Prompt — Stripe Checkout Session

Add Stripe billing to my Next.js 14 SaaS app.
I'm selling a single Pro plan at $9/month.

Create:
1. /app/api/stripe/create-checkout/route.ts
   - POST handler
   - Gets the current user from Clerk
   - Creates a Stripe Checkout Session with:
     * mode: "subscription"
     * price: my Pro plan price ID from env
       (STRIPE_PRO_PRICE_ID)
     * success_url: /dashboard?upgraded=true
     * cancel_url: /dashboard
     * customer_email: the user's email from Clerk
   - Returns the checkout URL

2. A "Upgrade to Pro" button component that calls
   this endpoint and redirects to the checkout URL

Use the Stripe Node.js SDK. My Stripe secret key
is in STRIPE_SECRET_KEY.

Prompt — Stripe Webhook Handler

Create a Stripe webhook handler at
/app/api/stripe/webhook/route.ts.

It needs to:
1. Verify the webhook signature using
   STRIPE_WEBHOOK_SECRET (this prevents fake requests)
2. Handle the "checkout.session.completed" event:
   - Get the customer's email from the event
   - Find the profile in my database where the
     email matches
   - Set is_pro = true for that profile
   - Set stripe_customer_id to the Stripe customer ID
3. Handle "customer.subscription.deleted":
   - Find the profile by stripe_customer_id
   - Set is_pro = false

Use the Supabase JS client for database updates.
IMPORTANT: The webhook route must export a config
that disables body parsing, or Stripe signature
verification will fail. Show me exactly how to
do this in Next.js 14 App Router.

Test mode vs. live mode

Stripe has two modes: test and live. In test mode, use card number 4242 4242 4242 4242 (any future expiry, any CVC) to simulate payments. No real money moves. Switch to live mode only when you're ready to accept real payments from real customers. Always develop and test in test mode first.

Step 5: The Public Profile Page

Every link-in-bio tool needs a public page at a URL like yourdomain.com/username. This is what users share with their audience. It's the product people actually see.

Prompt — Dynamic Public Profile Page

Create a dynamic public profile page at
/app/[username]/page.tsx.

This page should:
1. Accept a username from the URL parameter
2. Query the database for the profile where
   username matches
3. If no profile found, show a 404 page
4. If found, display:
   - The user's bio
   - All their links as clickable buttons
   - A small "Powered by LinkDrop" footer link
5. Use generateMetadata to set the page title to
   "[Username]'s links | LinkDrop" for SEO
6. This page should be server-rendered (no
   "use client") so it loads fast and gets indexed
   by Google

Use Tailwind CSS. Make it clean and mobile-first —
most visitors will be on their phones.

Step 6: Deployment — Making It Live

You have a working app running on your laptop. Now you need to put it somewhere the rest of the world can access it. Vercel is the answer — it was built by the same team that created Next.js, so the integration is seamless.

The deployment process:

  1. Push your code to a GitHub repository
  2. Go to vercel.com, click "Import Project," and connect your GitHub repo
  3. Add your environment variables (all the secret keys) in the Vercel dashboard
  4. Click "Deploy"

Environment variables checklist

Before deploying, make sure every key from your local .env.local file is added to Vercel's environment variables. Missing keys are the #1 reason apps that work locally break in production.

Prompt — Pre-Deployment Checklist

I'm about to deploy my Next.js 14 SaaS app to Vercel.
The app uses Clerk auth, Supabase PostgreSQL, and
Stripe billing.

Generate a pre-deployment checklist that covers:
1. Every environment variable I need to set in Vercel
2. Stripe webhook URL — what URL do I register in
   the Stripe dashboard after deployment?
3. Clerk allowed redirect URLs — what do I need
   to update in Clerk for my production domain?
4. Supabase connection — do I need to add my
   Vercel deployment URL to any allow-list?
5. A quick test plan: what 5 things should I test
   first after deploying to make sure nothing is broken?

After you get your Vercel deployment URL (something like linkdrop.vercel.app), go into your Stripe dashboard and update your webhook endpoint to https://linkdrop.vercel.app/api/stripe/webhook. This is the step people most often forget, and it means subscriptions don't activate in production.

What Can Go Wrong (and How AI Helps)

Building a SaaS always surfaces unexpected problems. Here are the most common ones and the prompts that fix them:

Stripe webhooks are not triggering

Debugging Prompt

My Stripe webhook at /api/stripe/webhook is not
receiving events in production. In development it
works fine with the Stripe CLI.

Here is my webhook route code: [paste code]

What are the most likely reasons a Next.js App Router
webhook route would receive events locally but not
in production on Vercel? Check for: body parsing
config, signature verification, environment variable
names, and HTTPS requirements.

Users can see each other's data

Security Audit Prompt

Review my API routes and identify any places where
a logged-in user could access or modify another
user's data.

Here are my API route files: [paste files]

For each route, confirm:
1. Is the user's Clerk ID being checked?
2. Is the database query filtered by that user's ID?
3. Could someone craft a request to access
   a different user's records?

Show me any vulnerable routes and the fix for each.

The Stack, Summarized

Here's every tool you used and what it's responsible for:

Tool Role in Your SaaS Free Tier?
Next.js Pages, routing, API endpoints ✅ Open source
Clerk User sign up, login, sessions ✅ Free up to 10k MAU
Supabase Hosted PostgreSQL database ✅ Free tier available
Stripe Payment processing, subscriptions ✅ Free (pay per transaction)
Vercel Deploy and host the app ✅ Free hobby tier

Total monthly cost for an early-stage SaaS: $0 until you hit meaningful scale. That's the real unlock. You can build, launch, and validate your idea without spending anything on infrastructure until you're making money.

Frequently Asked Questions

Yes — with important caveats. AI coding tools like Cursor can generate working code from plain-English descriptions, which means you can get surprisingly far without a CS background. The catch: you still need to understand what the pieces do (auth, database, billing) so you can give good instructions and catch mistakes. This guide is designed to give you that foundational understanding in plain language.

For vibe coders in 2026, a strong starting stack is: Next.js (React framework) for the frontend and API routes, PostgreSQL (via Supabase) for the database, Clerk for authentication, Stripe for billing, and Vercel for deployment. This stack has excellent documentation, a massive community, and AI tools like Cursor are extremely good at generating code for it — which matters a lot when you're building with AI as your main coding partner.

Authentication is the system that lets users sign up, log in, and stay logged in. For a SaaS app, you have two solid options: use a managed auth service like Clerk (fastest to set up, handles everything for you including password resets and session management) or use NextAuth.js (open-source, more control, runs inside your own app). For first-time builders, Clerk reduces the complexity significantly — you give your AI the integration instructions and it handles the hard security parts.

Stripe handles the payment side so you never have to touch credit card numbers. You create a subscription product and price in your Stripe dashboard, then add code that creates a Checkout Session when a user clicks "Subscribe." The user fills in their card on Stripe's hosted page, Stripe charges them, then sends a webhook notification to your app confirming the payment. Your app receives that webhook and unlocks the paid features for that user. The Stripe CLI lets you test the full flow locally without real money.

A webhook is a way for an external service (like Stripe) to automatically notify your app when something happens — a payment succeeds, a subscription is cancelled, a card expires. Instead of your app constantly asking "did anything happen?", Stripe sends a POST request to a special URL on your app the moment an event fires. Your app listens at that URL and updates its database in response. Every SaaS with billing needs at least webhook handlers for payment success and subscription cancellation.

Vercel is the easiest deployment option for Next.js apps — it was built by the same team that created Next.js. Connect your GitHub repository to Vercel, set your environment variables (Clerk keys, Stripe keys, database URL) in the Vercel dashboard, and click deploy. Every subsequent push to your main branch automatically triggers a new deployment. A basic app can be live in under 10 minutes from first push, and the free hobby tier covers everything you need at early stage.

What to Learn Next

You now have a complete mental map of what it takes to build a SaaS app with AI. Here's where to go deeper on each piece:

Also useful as you keep building:

The real lesson here

The hard part of building a SaaS with AI is not the code — it's knowing what to ask for. AI will write the Stripe webhook handler, the authentication middleware, and the database queries. Your job is to understand each layer well enough to give precise instructions, review what comes back, and catch the mistakes. That's a skill you build quickly. The first SaaS is the hardest. The second one takes half as long.