It's live isn't the same as it's ready: my MVP launch checklist
Last week Cursor launched live apps. You describe a tool, an agent builds it, sets up a database, runs security checks, and deploys it. You get a link you can share.
I think that’s great. Most side projects never leave localhost. Now they will.
But I keep getting the same question from founders: if a prompt gets me a live app, why would I pay someone to build my MVP?
Fair question. Here’s my honest answer.
If it’s an internal tool for your team, try the tools first. You might not need me.
If it’s a product strangers will sign up to and pay for, the link was never the hard part. The hard part is a list of boring decisions that no prompt makes for you. This post is that list. It’s the checklist I go through before a Next.js + Supabase MVP gets real users.
Use it on your own app, whoever (or whatever) built it.
1. Decide what v1 is, and write it down
Before any code, I write one short page:
- Who is the user?
- What’s the one thing they come to do?
- What does “done” look like for v1?
- What is explicitly not in v1?
The last line matters most. AI tools are happy to add features. Every extra feature is another thing to secure, test and support. A small v1 that works beats a big one that half works.
2. Row Level Security on every table
This is the one I see go wrong the most.
In Supabase, your database can be reached from the browser with the public anon key. That’s by design. What keeps users out of each other’s data is Row Level Security (RLS) and the policies you write.
So before launch:
- RLS is enabled on every table in the public schema. Not most. Every one.
- Each table has policies for select, insert, update and delete that match who should do what. Usually something like “a row belongs to
auth.uid()”. - Tables with no policies are fine only if nobody should touch them from the client.
Then test it like an attacker would, not like the owner:
- Create user A and user B.
- Log in as A, create some data.
- Log in as B and try to read, edit and delete A’s data, using the Supabase client directly in the browser console, not just the UI.
If B can see one row of A’s data, you’re not ready. The UI hiding a button is not security.
3. Keep the service role key on the server
Supabase gives you two keys. The anon key is meant for the browser. The service role key skips RLS completely.
Rules I follow:
- The service role key never goes in a
NEXT_PUBLIC_env variable. Anything with that prefix ends up in the browser bundle. - It’s only used in server code: route handlers, server actions, background jobs.
- Even on the server, I use it only where I really need to bypass RLS (admin jobs, webhooks), and I check permissions myself there.
Quick check: search your built client JavaScript for the key, or just search the repo for NEXT_PUBLIC_ and read every line.
4. Auth settings for the real domain
Things that work on localhost and break on launch day:
- The Site URL and redirect URLs in Supabase Auth still point at localhost or a preview URL. Magic links and password reset emails send people to the wrong place.
- Email confirmation is off because it was annoying in dev. Decide on purpose if you want it on.
- Emails come from the default sender. Supabase’s built-in email is meant for testing and has tight limits, so set up your own SMTP provider before real signups.
- OAuth providers (Google, GitHub) have the production callback URL added in their own consoles too.
Sign up with a fresh email on the production domain and go through signup, login, logout and password reset. All of it.
5. Storage has rules too
If users upload files, Supabase Storage has its own policies. A public bucket means anyone with the link can read the file.
- Use private buckets for anything user-owned.
- Write storage policies the same way as table policies: users can only reach their own folder.
- Serve private files with short-lived signed URLs.
Same test as before: can user B open user A’s file?
6. Payments: trust the webhook, not the redirect
If you take money with Stripe:
- Don’t mark someone as paid because they landed on your success page. Mark them paid when the webhook says so.
- Verify the webhook signature.
- Handle the same event arriving twice without giving someone two of anything.
- Decide what happens when a payment fails or a subscription is cancelled. Does the user lose access right away, at period end, never?
Use Stripe test mode and the Stripe CLI to replay events before you switch to live keys.
7. The database lives in migrations, not in the dashboard
It’s easy to click tables and policies together in the Supabase dashboard. Then nobody knows what production actually looks like.
I keep the schema and policies as SQL migrations in the repo (the Supabase CLI does this). That way:
- dev and production can be compared,
- a new developer can set it up from scratch,
- you can see in Git when a policy changed and why.
8. Know what happens when something breaks
Before real users:
- Errors are logged somewhere you’ll actually look (Vercel logs at minimum, an error tracker if you can).
- You know what your Supabase plan backs up and how you’d restore it. Check this now, not after a bad delete.
- There’s a way for users to reach you when something’s wrong.
9. Users can leave
Someone will ask to delete their account. Decide now:
- What gets deleted, and what has to stay (like invoices)?
- Does deleting the user in Auth also clean up their rows and files?
It’s a small feature. It’s also the kind of thing that’s very annoying to bolt on later.
10. It all runs on your accounts
This one isn’t technical, but it matters a lot.
The GitHub repo, the Vercel project, the Supabase project, the Stripe account, the domain. All of it should be in your name. Not your developer’s, not a tool’s workspace you can’t export from.
When I hand over an MVP, the code goes to the client’s GitHub and it runs on their own accounts. If I disappear tomorrow, they can hire anyone to keep going.
The short version
Before real users touch your app:
- v1 scope is written down, including what’s not in it
- RLS on every table, tested with two real users
- Service role key only on the server, nothing secret in
NEXT_PUBLIC_ - Auth URLs, email sender and OAuth callbacks set for production
- Storage buckets private where they should be, with policies
- Payments trusted from verified webhooks only
- Schema and policies in migrations in the repo
- Errors logged, backups understood
- Account deletion decided
- Everything on your own accounts
The new AI tools make the code fast. I use them every day. But “it’s live” and “it’s ready” are still two different things, and the gap between them is mostly decisions.
Want me to build yours?
My Next.js + Supabase MVP package is fixed price: login, database, admin, and an AI feature if you want one, live on Vercel and on your own accounts. If you already have an app and just want someone to go through this checklist with you, book a quick call and tell me about it.