DEV Community

Cover image for Lovable Supabase Integration: Cloud or Your Own Project, and How to Set It Up Safely
Tushar Bhendarkar
Tushar Bhendarkar

Posted on Originally published at tusharbhendarkar.com

Lovable Supabase Integration: Cloud or Your Own Project, and How to Set It Up Safely

If you connect your own Supabase project to Lovable and launch as is, your sign-up emails won't reach your customers. Supabase's built-in email only sends to members of your own Supabase team, and only two an hour. It's one of a handful of settings the Lovable Supabase integration leaves to you, and an easy one to discover only when your first real customer tries to sign up.

For my last post I sorted 264 public reports of broken Lovable apps. Sixty-eight of them were about Supabase: logins, connections and who can see what. The biggest single cause was the database access rules, switched off or open to everyone (12 reports), followed by confusion between Lovable Cloud and your own Supabase project (6) and security warnings that were never fixed, or turned out to be noise (6).

I build on Supabase myself. Launch Check and Client Approvals both run on it, so this is the setup I use, written for a Lovable app: which backend to pick, how to connect it, the settings Lovable doesn't do for you, and how I test that one user can never see another user's data.

Lovable Cloud or your own Supabase project?

Lovable Cloud is Supabase, run for you. It's built on Supabase's open-source foundation, each project gets its own Supabase project behind it, and it's switched on by default, so most Lovable apps never need a separate Supabase account. Lovable's Supabase docs give three reasons to connect your own project instead: owning the account and billing, full Supabase dashboard access, or reusing a project you already have.

Lovable Cloud Your own Supabase project
Who runs it Lovable You, in your Supabase account
How you pay Lovable credits Your Supabase plan (free tier to start)
Where you manage it Inside Lovable (Database, Users, Storage, Logs) The Supabase dashboard
Login settings and Google sign-in From the Lovable chat In Supabase and Google Cloud, by you
Branded emails Paid Lovable plans Your own email server (custom SMTP)
Backups and pausing Managed in Lovable Managed in Supabase
Switching later No automatic move either way Moving onto Cloud is not supported

My rule: Cloud for a prototype or an internal tool, my own Supabase project for anything I'd sell or hand over to a client. Then the database, its bill and its backups are in my name, and I can open it without going through a builder.

Whichever you pick, decide early. There is no automatic move between the two in either direction. Since July 3, 2026 you can export a Cloud database and remove Cloud from a project, but removing it permanently deletes the Cloud data, storage, logins and functions. One more trap: Lovable turns Cloud on automatically when a feature needs a backend, because the permission defaults to Always allow. If you want your own Supabase, change it to Ask each time under Connectors, Cloud, Manage my agent's permissions, before you build anything.

How to connect your own Supabase project

  1. Create a Supabase project. The free tier is enough to start, and the integration works on every Lovable plan.
  2. Link your Supabase organization once. A Lovable workspace owner or admin does this; other members can then connect projects from it without their own Supabase account.
  3. Connect the project. For a new app, click + in the prompt box, open Databases and pick your Supabase project. For an existing app with no backend yet, open More, Cloud and choose "Already have a Supabase project? Connect it here". That link disappears once Cloud is on.
  4. Check the Cloud view. It should show your Supabase project's name and status, with links to its dashboard.

From then on Lovable writes database changes as migrations, shows them for your approval, runs them and saves them in supabase/migrations. It deploys edge functions, stores keys for services like Stripe as Supabase secrets, and creates storage buckets when a feature needs uploads. One Lovable project connects to one Supabase project. Several Lovable projects can share one Supabase project, but they overwrite each other's secrets, which Lovable now warns about.

Diagram of a Lovable app on Supabase: the visitor's browser holds a public key and talks directly to Supabase Auth, Database, Storage and Edge functions; row level security rules guard the database and storage, and edge functions hold the secret service role key.
Your app's browser code talks to the database directly. The access rules on each table are what stop one visitor reading another's data.

The settings Lovable leaves to you

On your own Supabase project, Lovable's docs are clear that login settings, providers and email live in the Supabase dashboard, not in Lovable. These are the three I set before anyone else signs up.

Emails: add your own email server

Supabase's email docs say that without custom SMTP, auth emails only go to members of your Supabase organization, and real users get "Email address not authorized". The built-in service also sends at most two emails an hour and isn't meant for production. Add any SMTP provider (Supabase lists Resend, Postmark, AWS SES and others) under Authentication, SMTP Settings. The limit then starts at 30 emails an hour, and you can raise it.

Login addresses: Site URL and redirect URLs

The Site URL is where users land after confirming their email, resetting a password or signing in with Google. It starts as http://localhost:3000, and it must be your live address. Every other address your app sends people back to has to be on the Redirect URLs list under Authentication, URL Configuration. If it isn't, Supabase quietly sends the user to the Site URL instead, which is the classic "sign-in sends me to localhost" bug. Supabase's redirect docs suggest wildcards for preview addresses and exact paths for production. For Google sign-in, add Supabase's callback address as an authorized redirect in Google Cloud. Without your own branding or a custom domain, Google's consent screen shows your-project-id.supabase.co instead of your app's name.

Pausing on the free plan

Supabase pauses free projects after about a week with too little database activity, after emailing you a warning. Restore it from the dashboard with Resume project; paid plans are never paused for inactivity. One catch from Supabase's API key docs: the old anon and service_role keys are being retired by the end of 2026, and since November 2025 a project restored from a pause comes back without them. If your app still uses a long key starting with eyJ, plan the move to the new publishable key before a pause forces it.

Row level security, in plain English

Your app's code runs in the visitor's browser and talks to the database directly, using a publishable key that is public on purpose. Supabase's own analogy: the publishable key is taped to the front door and only opens the lobby, and the secret key is the master key that stays in your pocket. What decides which rooms the lobby key opens is row level security (RLS): rules on each table that act like a WHERE clause added to every query.

Lovable writes these rules for you and checks them after schema changes, but it still tells you to verify every table yourself before going live. One reason: tables created with SQL, which is how migrations create them, need RLS switched on explicitly. This is the standard pattern for data that belongs to one user, from Supabase's RLS guide:

alter table public.notes enable row level security;

create policy "Owners read their notes"
on public.notes for select
to authenticated
using ( (select auth.uid()) = user_id );

create policy "Owners add their own notes"
on public.notes for insert
to authenticated
with check ( (select auth.uid()) = user_id );

create policy "Owners edit their notes"
on public.notes for update
to authenticated
using ( (select auth.uid()) = user_id )
with check ( (select auth.uid()) = user_id );

create policy "Owners delete their notes"
on public.notes for delete
to authenticated
using ( (select auth.uid()) = user_id );

create index on public.notes (user_id);
Enter fullscreen mode Exit fullscreen mode

One policy per action makes it obvious what each rule covers. WITH CHECK stops someone creating a row that belongs to another user, or moving a row to someone else when they edit it. Wrapping auth.uid() in a select and indexing user_id are performance fixes: in Supabase's own benchmark on 100,000 rows, wrapping auth.uid() took a query from 179 ms to 9 ms, and indexing user_id took another from 171 ms to under 0.1 ms.

Rules that look safe but are not

  • A rule that lets everyone through. using (true) means RLS shows as enabled, and everyone gets in anyway. A read rule "to anon using (true)" gives every signed-out visitor every row.
  • Several rules on one table. They combine with OR, so the most generous one wins.
  • Roles kept in user_metadata. Users can edit their own metadata, so never base access on it. Keep roles in app_metadata or a table.

Things that skip RLS completely

  • The secret key (the old service_role key) ignores every rule. It belongs in edge functions only, and Lovable warns that server code using it must check permissions itself.
  • SECURITY DEFINER functions run as their owner, usually postgres, and anyone can call them by default, including signed-out visitors.
  • Views run as their creator too. On Postgres 15 and up, create them with security_invoker = true.
  • Storage has its own rules on storage.objects. Tight table rules don't protect an uploaded file, and a broad read rule on storage lets anyone list every file.

Supabase's Security Advisor flags most of these, and its production checklist starts with it. One more date for your calendar: from October 30, 2026, Supabase stops exposing new tables to the API automatically in existing projects, according to its announcement. A new table without an explicit grant then returns "permission denied for table" (error 42501), even if its RLS rules are right. Lovable's docs don't mention this yet, so if a new table suddenly returns 42501 after that date, a missing grant is the first thing I'd check.

How I test that one user can never see another's data

When I built Client Approvals, I wrote a database test that signs in as different people and tries to break the rules. A team member should see only their own workspace. They try to comment on another workspace's request, attach a comment to the wrong item, post while pretending to be the client, and upload a file into another workspace's folder. Another user tries to read those comments and list those files. A signed-out client with a share link should see exactly one request and nothing else. Every one of those attempts has to fail, and the test rolls everything back when it finishes.

Access test grid: the owner of the data can read, change and share it; another signed-in user and a signed-out visitor are blocked from reading, changing, adding records to other accounts, uploading into other folders and listing other files, and a shared link shows only that one item.
Sign in as each kind of person and try every action. Anything not marked allowed must fail, for files as well as tables.

The trap is testing in the wrong place. Supabase's SQL editor runs as the table owner, which ignores RLS, so a query that returns rows there proves nothing about what your users see. Use Supabase's user impersonation (in public beta), or run the check as a real role. This is the shape of it, inside a transaction so nothing is kept:

begin;

-- act as user B, signed in
select set_config('request.jwt.claims',
  json_build_object('sub', '<user B id>', 'role', 'authenticated')::text, true);
set local role authenticated;
select count(*) from public.notes where user_id = '<user A id>';  -- must be 0

-- act as a signed-out visitor
reset role;
select set_config('request.jwt.claims', json_build_object('role', 'anon')::text, true);
set local role anon;
select count(*) from public.notes;  -- must be 0

rollback;
Enter fullscreen mode Exit fullscreen mode

If you don't write SQL, do the manual version: create two normal accounts, add something private in each, then try to open one account's records and files while signed in as the other, and again while signed out. Both attempts must fail.

When the integration stops working

These are the problems that come up most, from the reports and from Supabase's own troubleshooting docs, with the fix for each:

  • "Supabase connection issue" in Lovable. Lovable can't find the project: it was deleted, or the workspace lost access to the organization. Disconnect, or use Manage organizations and pick the project again. Disconnecting deletes nothing.
  • Nothing loads right after turning on RLS. RLS with no policies blocks everything through the API. Add the policies the app needs.
  • Data won't load on Cloud. Lovable's list: the instance is too small, a query error, RLS blocking the query, or a paused backend that needs Wake up.
  • "Email address not authorized". No custom SMTP yet. See the email section above.
  • Users land on localhost after signing in. The Site URL or Redirect URLs list is missing your live address.
  • "Too Many Requests" at sign-up. Supabase allows 30 sign-up and sign-in requests per 5 minutes per IP address by default.
  • "Infinite recursion" (error 42P17). Two tables' policies read each other, which is common with sharing features. Move the check into a helper function in a private schema.
  • A scan warning you can't clear. Leaked password protection needs Supabase's Pro plan, so it can't be switched on for a free project.

Moving from Lovable Cloud to your own Supabase

It's possible, by hand. Lovable's migration guide says to keep the app running on Cloud while you build the new backend, and to switch only when it's complete. The schema, RLS policies, functions, triggers and storage bucket policies move with the migration files. Auth providers, secrets, table data, storage files, users and edge functions you move yourself.

The Cloud export is a PostgreSQL backup file that you restore with pg_restore, with limits of 15 GB of storage and one export a day, and it leaves out storage files, edge function code and secrets. Cloud projects changed since October 7, 2026 record their changes as Drizzle migrations, which supabase db push won't run, so apply them in the order the guide lists. The final switch is two files in the Lovable project, .env and supabase/config.toml. Only remove Cloud after the new backend works, because removal deletes the Cloud data for good.

The integration is the easy part

Connecting Lovable to Supabase takes a few clicks. What makes it production-ready is everything around the connection: emails that reach real people, login addresses that point at your live site, and access rules that you've actually tried to break. If your app is already misbehaving, I wrote up what breaks most often in Lovable app not working, and there are more guides in Fix an AI-built app.

And if you'd rather hand it over, I take these on as client projects: send me the app link and what you need.

Common questions

Is Lovable Cloud the same as Supabase?
Lovable Cloud is built on Supabase, and each Lovable project gets its own separate Supabase project behind it. The difference is who runs it: with Cloud, Lovable manages it, you see it inside Lovable and pay in Lovable credits. With your own Supabase project, the account, dashboard and bill are yours.

Should I use Lovable Cloud or my own Supabase project?
Cloud is fine for prototypes and internal tools, and it is the default. Use your own Supabase project when you want to own the account and billing, use the full Supabase dashboard, or reuse an existing project. Decide early: there is no automatic switch between the two in either direction.

How do I connect Lovable to my own Supabase project?
A workspace owner or admin links your Supabase organization once. Then, for a new project, click + in the prompt box, open Databases and pick the Supabase project. For an existing project that has no backend yet, open More, Cloud and choose "Already have a Supabase project? Connect it here". That link is missing once Cloud is on.

Why are my Supabase emails not reaching users?
Without your own email server (custom SMTP), Supabase only sends auth emails to members of your Supabase organization, and at most 2 an hour. Real users get "Email address not authorized". Add an SMTP provider such as Resend or Postmark under Authentication, SMTP Settings before you launch.

Why does Supabase say permission denied for my table?
Error 42501 means the role has no grant on the table, which fails before any access rule runs. From October 30, 2026, new tables in existing Supabase projects are no longer exposed to the API automatically, so each new table needs an explicit grant. If nothing loads right after you turned row level security on, the table has no policies yet.

How do I check my Lovable app's row level security?
Run Supabase's Security Advisor, then test as real users. Do not trust the SQL editor: it runs as the table owner and ignores the rules. Use Supabase's user impersonation, a test that sets a user's role, or sign in as two normal accounts and try to open each other's records. Both attempts must fail.

Can I move a Lovable app from Lovable Cloud to my own Supabase?
Yes, by hand. Export the Cloud database, rebuild the schema in a new Supabase project, then move auth providers, secrets, files, users and edge functions yourself, and switch the app's settings last. Keep Cloud running until the new backend is complete, because removing Cloud permanently deletes its data.


This post first appeared on tusharbhendarkar.com. I fix apps built with Lovable, Replit, Bolt and Base44, and I build free checkers for live apps. If something here is broken for you, email me at tusharbhendarkar44@gmail.com.

Top comments (0)