Supabase for Vibe Coding: Setup, Security and Limits
· 6 min read · Guides
Supabase is a good default backend for vibe-coded apps. It gives you Postgres, login, file storage and an API in one place, and most AI builders already know how to talk to it. The catch is that the AI won't secure it for you, so you need to turn on Row Level Security and check it yourself.
This guide covers why Supabase became the default, how to wire it into your tool, the security steps that matter, and where the free plan stops.
Why Supabase keeps showing up
A typical vibe-coded app needs the same four things: a database, user accounts, file uploads and somewhere to run a bit of server code. Supabase covers all four. Underneath it is plain Postgres, so the AI has a lot of training data on it and your data isn't locked into a odd format.
The tools have noticed. Lovable has a Supabase integration that connects a project you own and uses it as the app's backend. Lovable also ships its own built-in backend, and its docs say that backend builds on Supabase's open-source foundation. Other builders, like Reflex, offer a Supabase connector too. In Cursor or Claude Code you can connect through MCP (more on that below).
One practical point on Lovable: its docs say migrating from Supabase to the built-in backend isn't supported. So pick one early rather than hoping to switch later.
Setup: the boring, reliable path
- Create the project yourself in your own Supabase organization. Even if your tool can create one for you, you want to know where the dashboard lives.
- Connect it to your builder. In Lovable that's the Supabase integration. In other tools you'll usually paste the project URL and a key. Use the publishable key (older tutorials call it the anon key) for anything that runs in the browser.
- Let the AI create tables, but read the SQL. Ask for a migration, not a click-through. You want something you can read and re-run.
- Turn on RLS and write policies before you add real users.
- Test as two different users before you share the link.
Row Level Security is the part you can't skip
In a typical vibe-coded app, the browser talks to your database directly. That's fine, as long as the database decides who can see what. Supabase's docs say that for frontend apps you need to turn on RLS and configure policies that grant the least privilege your app needs. They add that the publishable key is safe to expose only with RLS on.
If RLS is off on a table the browser can reach, anyone with your public key can read or write it. That is the most common way an AI-built app leaks data, and the AI will happily build a working app without ever mentioning it.
A starter policy
The usual first rule is that users can only touch their own rows. The pattern from Supabase's docs looks like this (swap user_id for whatever your column is called):
alter table public.notes enable row level security;
create policy "Users manage their own notes"
on public.notes
for all
to authenticated
using ( (select auth.uid()) = user_id )
with check ( (select auth.uid()) = user_id );
The using part checks existing rows. The with check part stops someone from inserting a row that belongs to somebody else.
Expect one surprise. Once RLS is on, queries return zero rows until a policy exists. If your app suddenly looks empty after you enable it, that's usually why, not a bug.
A prompt you can paste
Audit my Supabase schema for security. For every table in the public
schema: confirm Row Level Security is enabled, list the policies, and
flag any table that is readable or writable without logging in.
Propose a migration that adds owner-only policies using
(select auth.uid()) = user_id. Don't run anything yet. Show me the SQL
first, and tell me which tables should stay public on purpose.
The last line matters. A public blog-posts table is fine. A public profiles table with email addresses is not. Review what the AI proposes rather than approving it in bulk.
Check it yourself
- Open the Table Editor and look for tables showing RLS as disabled.
- Sign in as user A, create a row, then sign in as user B and try to load it. You shouldn't be able to.
- Log out and try to load the same data. You shouldn't be able to do that either.
- Check that secret keys aren't in client code or committed to Git. Anything with full access belongs in server-side environment variables or edge function secrets.
Using Supabase MCP in Cursor or Claude Code
Supabase runs a hosted MCP server that lets your AI editor inspect and change your project. It's handy for schema design and debugging, and it includes a tool that pulls security and performance advisors. But Supabase's own docs say that connecting an LLM to your projects carries security risks.
Their advice is to scope the server to one project, turn on read-only mode, and limit which feature groups are enabled. The docs also say never to connect it to production data. A scoped URL looks like this:
https://mcp.supabase.com/mcp?project_ref=YOUR_DEV_PROJECT&read_only=true
My habit: use a separate dev project with fake data for MCP, and keep the real project for the deployed app. It's a few extra minutes of setup, and it means a bad prompt can't touch real users.
What the free plan gets you
Free is enough to build and show a prototype. Plan details change, so check Supabase's pricing page before you commit. As of recent third-party breakdowns, it looks like this:
| Item | Free plan |
|---|---|
| Active projects | 2 |
| Database size | 500 MB each |
| File storage | 1 GB |
| Egress | 5 GB |
| Monthly active users | 50,000 |
| Inactivity | Paused after about a week |
Those numbers come from CloudZero's pricing breakdown, which also lists Pro at $25 per organization per month plus usage. It warns that the base fee is a floor, not the final bill, because compute, egress and storage stack on top.
The pause is the one that bites. A weekend project you forget about for a week will go to sleep, and a link you shared will stop working. If real people depend on the app, plan on a paid tier.
Common mistakes in AI-built Supabase apps
- Tables with no RLS. The AI makes the feature work and moves on.
- Policies that are too loose. A policy that lets any logged-in user read everything is only slightly better than no policy.
- One project for dev and prod. Experiments and real data end up in the same database.
- Secret keys in the frontend. If a key can bypass your policies, it must never ship to the browser.
- Schema changes made by chat only. Ask for migrations and commit them, so you can rebuild the database if something breaks.
A sensible order of work
Build the feature first, then run the audit prompt, then test with two accounts. Do this before launch, not after the first bug report. For Lovable specifically, remember that its own docs list the Supabase connection as billed by Supabase, and that backups and pausing are yours to manage when you connect your own project.
FAQ
Is Supabase free for a vibe-coded side project?
Yes, within limits. The free plan covers two active projects with a 500 MB database each, and projects pause after about a week of inactivity. That's fine for prototypes and demos. For anything people rely on, look at the paid plan and check current pricing on Supabase's site.
Do I need Supabase if my tool has its own backend?
Not always. Lovable, for example, includes a built-in backend, so you can start without a separate account. Connect your own Supabase project if you want direct dashboard access, to share data with other apps, or to control billing and backups yourself. Decide early, since Lovable says it doesn't support migrating from Supabase to its built-in backend.
Is it safe to let my AI editor use the Supabase MCP server?
It's safe enough for development if you set it up carefully. Scope it to one dev project, use read-only mode where you can, keep per-call approvals on, and never point it at production data. Supabase's docs describe these as best practices, and they don't claim the guardrails are a guarantee.
Cover photo: Anthony Riera on Unsplash