How to Build a SaaS MVP with Claude Code: A Realistic Walkthrough

Sanket Chaukiyal

April 25, 2026

The “build a SaaS in a weekend with AI” pitch is mostly hype. Auth, payments, a database that survives a deploy, a webhook that does not silently double-charge a customer: those take real work, even with an agent that can edit twenty files in parallel. They also do not take six months. The honest range for a focused first version, with one developer and Claude Code on Pro or Max, is ten to eighteen days of concentrated work. This is the realistic walkthrough.

The two-week answer

Build a SaaS MVP with Claude Code in roughly fourteen days using Next.js 16 on the App Router, Supabase for Postgres plus Auth, Stripe for billing, and Vercel for hosting. Days 1 to 2 scope and scaffold. Days 3 to 6 build the one core feature. Days 7 to 9 wire magic-link auth with row-level security, then Stripe Checkout and webhook handlers. Days 10 to 14 polish, set up production secrets, ship to a real domain. Realistic API spend during the build: $80 to $250 with prompt caching on, $300+ without. Post-launch services run about $25/month for Supabase Pro plus $0 to $20 for Vercel. Stripe takes 2.9% plus 30 cents on every successful US card charge.

Stack optionRecommendedAlt 1Alt 2
Frontend / frameworkNext.js 16 (App Router, Turbopack, TypeScript)Remix on ViteSvelteKit
Database + authSupabase (Postgres, Auth, RLS)Neon Postgres + ClerkSupabase + Clerk (mix)
BillingStripe Checkout + Billing PortalLemon Squeezy (MoR for VAT)Paddle (also MoR)
HostingVercel (Hobby for build, Pro at launch)RailwayFly.io
Build-phase API spend$80–$250 with caching onsame (Claude Code is the variable, not the stack)same
Post-launch monthly services$25 Supabase Pro + $0–$20 Vercel$0–$19 Neon + $25 Clerk$25 Supabase + $20 Vercel
Vendor lock-inModerate (Postgres portable, Auth less so)High on Clerk’s user modelModerate; Lemon Squeezy MoR is a tax win
Build speed with Claude CodeFastest (CLAUDE.md is referenced by create-next-app)Fast; Remix patterns are well-knownSlower; less Claude training data
Deploy storyPush to GitHub, Vercel deploys; Stripe CLI for webhook tunnelRailway from GitHubFly launch from CLI
The recommended stack for a 2026 SaaS MVP built with Claude Code, alongside two viable alternative stacks. The recommended column reflects what Claude Code, Next.js 16, and Supabase have converged on as a default in April 2026. Lemon Squeezy and Paddle are merchant-of-record options that handle international tax compliance in exchange for slightly higher per-transaction fees than vanilla Stripe.

What “SaaS MVP” realistically means

A SaaS MVP is a hosted application that solves one problem for a paying user. It has a sign-up flow that holds up against email spam, a database that persists data across deploys, a payment integration that takes real money and charges it again next month, and one feature that delivers value the moment a user logs in. Strip any and the thing is a demo with a Stripe button, not a SaaS.

That bar rules out a single-page Next.js app with a fake login, a Notion-template directory, a tool that generates PDFs and asks for a tip on Gumroad. Those can be useful. They are not SaaS, and a walkthrough that pretends they are sells a softer thing under a harder name.

Honest scoping, the 80/20 of SaaS MVPs

The most expensive mistake in MVP development is building features the first hundred users will not touch. Resist team accounts, role-based permissions, an audit log, a public API, light/dark themes, A/B testing. Those belong in months three through six.

What stays in scope: one core user-facing feature, magic-link auth, single-tenant data with row-level security, Stripe Checkout for a single paid plan, a usage dashboard, and a cancellation flow. Roughly eight components. Claude Code can scaffold all eight in two weeks if the prompts stay tight and the test data is realistic. Write the list on day one, paste it into your CLAUDE.md, let the agent see it before every session. Scope drift is what kills the timeline; every “while we’re at it” adds a day.

Setting up Claude Code for a SaaS project

Install Claude Code via the recommended path: curl -fsSL https://claude.ai/install.sh | bash on macOS or Linux, irm https://claude.ai/install.ps1 | iex on Windows PowerShell, or Homebrew (brew install --cask claude-code). The npm install still works but is no longer the recommended method as of April 2026.

Sign in with Pro or Max. Pro is $20/mo or $17 annual ($200 up front); Max starts at $100/mo with materially higher Claude Code caps. For a fourteen-day sprint at four to six hours daily, Pro is enough if you stay on Sonnet for routine work and reach for Opus for harder refactors. Max is the right call once you run parallel agent teams for review, lint, and security audits while editing. Leon Furze’s February 2026 write-up of building five static content sites with Claude Code ran on Max and noted the tool can spawn an “agent team” for parallel work. A SaaS MVP makes the pattern more useful, not less.

Scaffold the project: pnpm create next-app@latest my-app --yes (or npm/yarn/bun equivalents). The --yes flag accepts defaults: TypeScript, Tailwind CSS, ESLint, App Router, Turbopack, import alias @/*. create-next-app now ships an AGENTS.md with a CLAUDE.md that references it, so Claude Code reads framework conventions on first session. The two tools converged on a shared file; an agent opening your repo immediately knows how App Router, Server Components, and Turbopack work.

Add a project-level CLAUDE.md next to the auto-generated one. Put your eight-component scope list, the database schema as you build it, and a “do not do” section so the agent stops re-proposing rejected ideas. The CLAUDE.md is the agent’s memory across sessions; the more concrete, the less you correct.

The 14-day walkthrough

Treat the day numbers as a representative middle case for one developer working four to six hours daily. Realistic scopes shift this to ten days at the optimistic end (you have built this stack before) or eighteen at the pessimistic end (your core feature has a non-trivial algorithm or third-party integration).

How to Build a SaaS MVP with Claude Code: A Realistic Walkthrough

Day 1, scope and decisions. Product description, eight-component list, pricing model. Buy the domain, open the GitHub repo, open Stripe in test mode, open a Supabase project on Free, reserve the Vercel project name.

Day 2, scaffold and CLAUDE.md. Run create-next-app, push to GitHub, link to Vercel. Write the CLAUDE.md scope. Install @supabase/supabase-js, stripe, the Stripe CLI. First Claude Code session: ask for lib/supabase/server.ts and lib/supabase/client.ts following the App Router cookie-based session pattern. Verify the dev server. Commit.

Day 3, database schema and migrations. Three tables is usually enough: profiles, the core domain table, and subscriptions (the Stripe-mirror table). Write migrations as SQL files in supabase/migrations, apply via the Supabase SQL editor. Enable RLS on all three. Real policies land tomorrow.

Day 4, magic-link auth and RLS that actually works. Implement signInWithOtp with emailRedirectTo pointing at /auth/callback. Add the Site URL and callback to Supabase’s URL Configuration. Build the callback that exchanges the token hash via verifyOtp({ type: 'email' }) and persists the session cookie. Smoke-test the loop end to end.

Then RLS. The pattern Supabase documents for user-scoped data is:

alter table profiles enable row level security;

create policy "User can see their own profile only."
  on profiles for select
  to authenticated
  using ( (select auth.uid()) = user_id );

create policy "Users can update their own profile."
  on profiles for update
  to authenticated
  using ( (select auth.uid()) = user_id )
  with check ( (select auth.uid()) = user_id );

Targeting to authenticated scopes the policy to logged-in users; wrapping auth.uid() inside a SELECT lets Postgres cache the result per statement instead of per row (a documented Supabase performance recommendation). Repeat for the core domain table. Test by signing in as two emails and confirming user A cannot read user B’s rows.

Day 5, first 60% of the core feature. Data model plus create/read paths. Write the app/(app)/dashboard/page.tsx server component that lists the user’s data and the form that creates a row. Server actions, not API routes, for mutations.

Day 6, the other 40%, including the part that surprised you. Edit and delete, validation, error states, empty-state UI. One piece will turn out harder than the spec suggested. Budget half of day 6 for it.

Day 7, Stripe products and the buy button. Create the product and price (monthly plus annual) in Stripe’s test-mode dashboard. Pin price IDs into lib/stripe/config.ts. Build the upgrade button that POSTs to /api/checkout, which calls stripe.checkout.sessions.create with the price ID, user email, success_url, cancel_url. Test with card 4242 4242 4242 4242.

Day 8, webhooks. This gets its own H2 below. Plan the full day. The webhook is the one piece that has to be correct on the first try because Stripe’s retry logic punishes you if it isn’t.

Day 9, Customer Portal and cancellation. Stripe’s Billing Portal handles “update card”, “see invoices”, “cancel plan” out of the box. Build the route that creates a portal session and redirects. Cancellation flags cancel_at_period_end = true locally; the webhook clears access when Stripe fires customer.subscription.deleted.

Day 10, transactional email. Supabase handles magic links. Stripe sends the paid-signup receipt if you toggle “Email customers”. Production-grade transactional email goes post-launch.

Day 11, production environment and secrets. Stripe test to live keys. Set Vercel env vars: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, STRIPE_SECRET_KEY (live), STRIPE_WEBHOOK_SECRET (live), service-role key for server-only writes. Register a live-mode webhook endpoint at /api/stripe/webhook. The signing secret differs from test mode; that is intentional.

Day 12, polish. Empty states. 404 page. Landing page above the fold. Pricing copy. Privacy policy and terms. Favicon. OG image. The “we are sorry” email for failed webhooks.

Day 13, smoke test in production. New email signup, magic-link flow, dashboard, core feature, upgrade, pay with a real card, confirm the webhook lands, confirm RLS holds across two accounts, cancel via the portal, refund yourself.

Day 14, launch. Point the domain at Vercel, confirm SSL, brand Stripe Checkout, post on whichever channel reaches the first hundred users. Open analytics. Wait.

Day 15 onwards is operations. Every fix gets weighed against, “will this make the next ten paying customers more likely to keep paying?” If no, it stays on the backlog.

The Claude Code workflow that actually works

Furze’s pattern for static sites (“ask for changes either in bulk or one at a time”) holds for SaaS with one adjustment: SaaS work is changes in tight loops with the dev server running and the database state visible.

next dev in one terminal, claude in another. You give Claude Code the file and a one-paragraph description. It edits, you save, the dev server hot-reloads, you click the thing it changed, you tell it what is still wrong. Five iterations, ten minutes.

Three things this rewards. Plan mode for non-trivial changes (Shift+Tab forces an outline before files get touched; catches “I assumed your schema had a created_at column” mistakes pre-commit). Agent teams for parallel review (one agent for a security pass, one for lint, one for “does this match the CLAUDE.md scope”; merge results). Hooks for guardrails (pre-commit npm run lint, post-edit typechecker).

Furze noted, with mild horror, that “if you don’t know what you’re doing… you can inadvertently delete files, including critical system files.” Same risk applies here. Keep Claude Code on the default “ask before destructive actions” permission. Commit early and often.

For lighter examples of the same loop, a calculator website with Claude AI from prompt to deploy and a simple HTML5 game with Claude Code in one afternoon walk through the specify-render-test-refine pattern on lighter scaffolds. The free-tier marketing-site equivalent, a portfolio website with free AI models in one to three hours, shows the loop without auth or a database to keep aligned.

The integration that breaks everyone, Stripe webhooks

Stripe webhooks are where Claude Code’s first attempt usually fails, and where copy-pasted Stack Overflow answers definitely fail. Five pieces have to be right.

Signature verification, on the raw body

Stripe signs every event with the signing secret and ships it in the Stripe-Signature header. To verify, you need the raw request body, the header, and the endpoint secret. Stripe’s docs are explicit: “Stripe requires the raw body of the request to perform signature verification.” Default timestamp tolerance is five minutes.

In Next.js 16’s App Router, this is the trap. Route handlers parse JSON if you call request.json(). You do not want that. You want request.text() to read the raw body, then pass that string to stripe.webhooks.constructEvent(rawBody, signature, secret). Reading request.json() first and stringifying it back loses the original bytes; verification fails with No signatures found matching the expected signature for payload.

// app/api/stripe/webhook/route.ts
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const secret = process.env.STRIPE_WEBHOOK_SECRET!;

export async function POST(req: NextRequest) {
  const body = await req.text();
  const sig = req.headers.get('stripe-signature') ?? '';

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(body, sig, secret);
  } catch (err) {
    return new NextResponse(`Webhook Error: ${(err as Error).message}`, { status: 400 });
  }

  // Idempotency check first, then async dispatch
  // ...
  return NextResponse.json({ received: true });
}

Idempotent handlers, because Stripe will resend

Stripe retries: live mode for up to three days with exponential backoff, sandbox three times over a few hours. Your endpoint will see the same event twice if it ever returns a non-2xx, and occasionally even when it returns 2xx. Guard “by logging the event IDs you’ve processed, and then not processing already-logged events.”

A stripe_events table with event.id as a unique constraint is the cleanest shape. Insert first; if it succeeds, do the work. If it conflicts, return 200 because someone already handled it. Postgres’ INSERT ... ON CONFLICT (id) DO NOTHING RETURNING id collapses that into one round trip.

Return 2xx before the slow stuff

The other Claude Code first-pass failure is awaiting a database write before responding. If your handler does await sendEmail(...) and the email service hiccups, you return 5xx, Stripe retries, your DB write fires twice, the user gets two welcome emails. The order: verify, dedupe, persist the event row, return 200, then dispatch the business logic to a queue. Stripe’s docs put it baldly: “Configure your handler to process incoming events with an asynchronous queue.”

Test and live modes have separate signing secrets

Both can point at the same URL but the secrets differ. Set STRIPE_WEBHOOK_SECRET to the live secret in production and a different value in development. Mixing them up is the single most common postmortem cause when a working webhook breaks after a deploy.

Local dev uses the Stripe CLI, not ngrok

stripe listen --forward-to localhost:3000/api/stripe/webhook prints Ready! Your webhook signing secret is whsec_... on first run. Paste it into .env.local as STRIPE_WEBHOOK_SECRET, restart next dev. The CLI tunnels live test events into your handler without exposing your laptop to the public internet.

Miss any one of the five and the webhook fails silently in a way that takes an afternoon to find. Spend the day budgeted on day 8.

Cost reality check

The “hundreds in API spend” sticker shock is real but it is not a black box. Three buckets.

Build-phase API, $80 to $250 typical

Anthropic‘s rate card for Claude Opus 4.6 (and 4.7, same headline price) is $5 per million input tokens, $25 output. Cache reads are $0.50 per million, ten cents on the dollar. During Claude Code sessions, your input bill is dominated by re-reads of CLAUDE.md, the file under edit, and prior turn context. With prompt caching on (default), most re-reads bill at $0.50 per million instead of $5, the single biggest cost lever. The output side bills heavily during extended-thinking debugging; $25 per million adds up faster than developers expect.

For a 14-day build with caching on, roughly 60% of API spend lands in the messy middle (days 5 to 9 when feature, auth, and webhooks all need real iteration), 25% during polish-and-fix (days 11 to 13), the rest on lighter days. Heavy extended thinking during webhook debugging can push the total past $300; light plan-mode and one-shot edits keep it under $100.

Opus 4.7 caveat: Anthropic’s April 16, 2026 release ships at the same headline price as 4.6, but the new tokenizer “may use up to 35% more tokens for the same fixed text” per Anthropic’s docs. Same prompts cost more in dollars even at unchanged per-token rates. SWE-bench Verified jumped from 80.8% on 4.6 to 87.6% on 4.7, so the extra cost buys real capability. For the model trade-offs, the real ranking of top frontier AI models for April 2026, beyond marketing headlines covers the Opus 4.6 vs 4.7 vs Sonnet 4.6 picture.

Post-launch services, $25 to $45 a month

Supabase Pro is $25/mo with 8 GB Postgres, 100,000 MAU for Auth, 100 GB storage, 250 GB egress. The free plan (500 MB DB, 50,000 MAU, 1 GB storage, 5 GB egress) pauses after seven days idle, which kills any production trajectory. Vercel Hobby is free at 100 GB Fast Data Transfer, 1M function invocations, 100 deploys/day. Vercel Pro is $20/user/mo with $20 of included usage credit and 1 TB transfer. Hobby works through the first hundred-ish paying customers, but Vercel reserves Hobby for non-commercial use, so plan the upgrade before serious revenue.

Transaction fees, scaling with MRR

Stripe takes 2.9% plus 30 cents on every successful US card charge. International cards add 1.5%. Currency conversion adds another 1%. A $20/mo subscription costs 88 cents in Stripe fees, or roughly $10.56 a year per subscriber. A hundred paying users at $20/mo is $2,000 in revenue and about $88 in fees; a thousand is $20,000 and about $880. Refunds: Stripe keeps the 30-cent fixed component. Disputes: $15, waived if you win.

Stacked bar chart showing twelve months of total monthly cost for a SaaS MVP built with Claude Code, broken into three buckets: Claude Code API spend, fixed services costs (Supabase Pro at $25 a month from month 2 onward, plus Vercel Pro at $20 a month from month 6 onward), and Stripe transaction fees scaling with paying-user count. Month 1 is the 14-day build month at roughly $200 in API spend, $0 services, $0 fees, no paying users. Months 2 through 5 hold services flat at $25 and ramp Stripe fees from $9 at 10 users to $70 at 80 users while API spend drops to $15 to $25 in maintenance mode. Month 6 services jump to $45 as Vercel Pro is added at 110 users, $97 in fees. Months 7 through 12 services hold flat at $45 while Stripe fees ramp from $123 at 140 users to $202 at 230 users. The chart visualises two patterns: build phase is API-heavy and one-time, and ops phase is services-flat with transaction fees becoming the largest cost component once paying users cross roughly fifty. All dollar figures are representative of vendor list prices verified April 2026.
A representative twelve-month cost profile for a SaaS MVP built with Claude Code on Supabase, Vercel, and Stripe. API spend concentrates in month 1 then drops to maintenance level. Services hold flat once Supabase Pro and Vercel Pro are on. Transaction fees scale linearly with paying-user count and overtake services around the fifty-user mark. Sources: Anthropic API rate card, Supabase pricing, Vercel pricing, Stripe US pricing, all verified April 2026.

What Claude Code will not do for you

A short list, because the alternative is a longer disappointment.

It will not write your product spec. The CLAUDE.md you author is the spec; if it is vague the code will be vague.

It will not pick the price. Pricing is judgment about willingness to pay; Claude Code can A/B between $9, $19, and $29 in the codebase but it cannot tell you which one converts.

It will not stop you from leaking the Supabase service-role key. That key bypasses RLS; if it lands in client-side code, your database is open. Spawn a security agent that greps for SERVICE_ROLE in the client bundle on every PR.

It will not handle GDPR or CCPA. If you serve EU users, you need a privacy policy, a cookie-consent path, and a data-export endpoint. Termly generates the documents but you still wire the export and delete flows yourself.

It will not protect you from your own scope drift. The CLAUDE.md is the discipline; without it the agent will cheerfully build the team-accounts feature you said you wouldn’t.

Frequently asked questions

Can a complete beginner build a SaaS MVP with Claude Code in two weeks?

No, with one caveat. A beginner can ship a static brochure site with Claude Code in an afternoon. A SaaS MVP requires enough familiarity with Postgres, environment variables, and webhook concepts to recognize when the agent is wrong. Two weeks assumes the developer has shipped one production web app before. A first-timer can still finish, but plan four to six weeks and a few evenings of debugging the agent cannot solve alone.

Why Next.js plus Supabase plus Stripe plus Vercel and not a different stack?

Because as of April 2026 it has the most public training data, the cleanest integration story, and the fewest bespoke patterns. create-next-app ships an AGENTS.md and CLAUDE.md by default. Supabase wraps Postgres, Auth, and storage behind one SDK. Stripe’s docs are unusually complete. Vercel deploys Next.js without configuration. Swapping one is fine; swapping all four turns a fourteen-day build into a research project.

Should I use the Claude API directly during the build, or only Claude Code?

Use Claude Code on Pro or Max for the build. The flat fee is more predictable than the metered API at build-phase volumes. The Claude API matters if your SaaS calls Claude on behalf of users. Treat that as a separate cost line and apply prompt caching aggressively, because user-facing workloads have high cache hit rates on system prompts.

Can I skip auth and payments and call it a SaaS MVP?

No. Auth and payments are what make a SaaS a SaaS. Without auth, it is a web tool; without payments, it is a free product. Both are deliberate categories. Ship the right thing under the right name.

How does Claude Code’s agent-teams pattern change the build?

It compresses review work. A solo developer can run lint, security audit, accessibility audit, and copy review in parallel rather than sequentially, which roughly doubles the safe-shipping rate in the second week. Parallel agents consume more tokens, so the cost-vs-time curve flattens. You trade dollars for days. On a SaaS MVP it handles RLS audits and Stripe-handler reviews particularly well.



Sanket Chaukiyal — Editor at Smart Chunks

Sanket Chaukiyal

Technology editor • 12+ years in editorial

Sanket is the founder and editor of Smart Chunks. He spent over six years at Autocar India (Haymarket SAC Publishing) as Sub Editor and Senior Copy Editor, and later served as Account Director (Content) at Rite Knowledge Labs. He holds a Master's in Media and Communication from the Symbiosis Institute of Media and Communication.

All articles → LinkedIn