Part of Host AI-built appsHost AI-built apps · Guide

Replacing Supabase in an app exported from Lovable or another AI builder.

If the app mostly uses Supabase as a database, moving off it is a contained job: copy the Postgres tables, move browser queries behind server routes, pick an auth option. If it leans on Supabase Auth, Row Level Security, realtime and edge functions, replacing them is a rewrite of those parts. Then keeping Supabase is usually simpler.

Facts checked

First, find out which Supabase pieces the app uses

Apps from Lovable, Bolt and similar builders talk to Supabase through supabase-js, so a few searches tell you how deep it goes. Run these from the repository root (adjust src to wherever the code lives):

grep -rn "supabase.from(" src | wc -l        # tables queried from the browser
grep -rn "supabase.rpc(" src                   # Postgres functions called directly
grep -rn "supabase.auth" src                   # sign-up, sign-in, sessions
grep -rn "supabase.storage" src                # file uploads and public URLs
grep -rn "functions.invoke" src                # edge functions
grep -rn "supabase.channel" src                # realtime subscriptions
ls supabase/migrations supabase/functions      # schema history and function code

What each piece becomes

The database is the easy part. The work is in everything Supabase does around it.

Supabase pieceHow the app uses itOn CannerWork
Postgres tablesYour data, read through supabase.from(…).A Canner Postgres database, connection string injected as DATABASE_URL.Small: copy the data (below).
Browser queries and Row Level Security †The browser queries tables directly; policies such as (select auth.uid()) = user_id decide which rows each user gets.No HTTP API sits in front of the database, and by default it is reachable only from inside Canner. Each query becomes a server route that checks who is asking.Usually the largest job: one route per kind of query.
Auth †supabase.auth for sign-up, sign-in and sessions. Users live in auth.users.Canner Auth (passkeys), an auth library in your app, or keep Supabase Auth.Medium to large, depending on the option.
Storagesupabase.storage uploads from the browser and public file URLs.A private S3-compatible bucket per project, reachable only from your app’s server code.Medium: uploads go through a route, files are copied once.
Edge Functions †supabase.functions.invoke(…), running on Supabase’s Deno-compatible runtime.Canner has no Deno runtime. Port each function to a route in your app.Small per function.
Realtimesupabase.channel(…) subscriptions to table changes.Nothing equivalent. Postgres LISTEN/NOTIFY works on Canner connections; pushing changes to the browser is your server’s job.Medium, or keep this part on Supabase.

† Competitor details come from each vendor’s own published pages on the dates shown; prices and plans change, so check the vendor before you decide. Browser queries and Row Level Security (2026-10-29) · Auth (2026-10-29) · Edge Functions (2026-10-29)

When keeping Supabase is simpler

Be honest about the count from the first step. If you found dozens of supabase.from calls, several RLS policies, realtime channels and edge functions, you are not swapping a database. You are writing a backend. That can be worth it, but it is not a migration.

A middle path: host the frontend on Canner and keep Supabase as the backend. Set VITE_SUPABASE_URL and the anon key as environment variables before the build, because Vite bakes them in at build time. Supabase has a Montréal region (AWS ca-central-1), so the data can stay in Quebec. Supabase is a US company, though, so a Montréal region does not take it out of reach of US orders; see data sovereignty.

Move the Postgres data

Create the database on your project, then pull the whole Supabase database in with migrate-in. It streams from the source with no local file and needs an empty target:

  • Which connection string. Supabase recommends its direct connection for pg_dump-style work. On the Free and Pro plans that connection is IPv6 only; if your side can’t reach it, use the session pooler on port 5432. Never the transaction pooler on 6543 (Supabase docs).
  • Why it may stop. Canner restores all or nothing. A Supabase database also holds its own auth and storage schemas, extensions Canner doesn’t install, foreign keys pointing at auth.users, and policies naming the authenticated role or calling auth.uid(). Outside Supabase none of those exist. An extension stops it with: The dump creates an extension that Canner databases do not allow you to install.
  • Before you leave, export the user list (select id, email from auth.users). Your tables reference those ids, and you will need them to match people up in the new auth system.
canner db init
export SUPABASE_DB_URL='postgresql://…'   # direct connection, or session pooler (port 5432)
canner db migrate-in --from-env SUPABASE_DB_URL

If migrate-in stops: copy only your tables

Dump only the public schema, let a throwaway local Postgres drop whatever depends on Supabase, and import the clean copy. The errors pg_restore prints in step 2 are worth reading slowly: each skipped policy or foreign key is a rule your server code now has to enforce.

# 1. Your tables only, without owners or grants
pg_dump "$SUPABASE_DB_URL" --schema=public --format=custom \
  --no-owner --no-privileges -f supabase.dump

# 2. Restore into a throwaway local Postgres. pg_restore skips what it can't
#    create and prints an error for each one: that list is your to-do list.
docker run -d --name scratch -e POSTGRES_PASSWORD=x -p 5433:5432 postgres:17
pg_restore --no-owner --no-privileges \
  -d postgresql://postgres:x@localhost:5433/postgres supabase.dump

# 3. Dump the clean copy and import it into Canner
pg_dump postgresql://postgres:x@localhost:5433/postgres \
  --format=custom --no-owner -f clean.dump
canner db import clean.dump

Auth: three options

  • Canner Auth (passkeys). Canner stores the user and the public key; your server verifies a short-lived ES256 token against a public JWKS and keeps no users table. Free up to 1,000 monthly active users, 125,000 on Live. It is passkeys only: no passwords to import, so each existing user enrols a passkey from an emailed link. That email is capped per organization per day (50 on Starter, 5,000 on Live), so moving 2,000 users on Starter takes weeks. On a paid plan your backend can mint enrolment tickets with the secret key instead, which sends no email. The token carries the email; match it to your exported auth.users id on first sign-in. Setup is in the passkeys docs.
  • An auth library in your app, using your Canner Postgres. Supabase stores passwords as bcrypt hashes, and Better Auth’s migration guide reads auth.users and auth.identities so users keep their passwords. Social logins need their OAuth callback URLs changed to your new domain.
  • Keep Supabase Auth and move everything else. The least code to change, but sign-in still depends on Supabase.

Files

Each Canner project has a private, S3-compatible bucket (how it works). Create a credential under Files → API access and add the values it shows to your environment variables; they are not injected automatically. Object keys must start with the project’s slug, and the client needs forcePathStyle: true.

The endpoint is reachable only from apps running on Canner, not from your laptop or CI. That changes two things. A browser upload that went straight to Supabase now goes to a route in your app, which writes to the bucket. And the one-time copy runs inside the deployed app (a protected admin route that pulls each file from Supabase and writes it to the bucket), or, for a few files, through the upload button on the Files tab. If your tables store full Supabase URLs for avatars and attachments, rewrite them to keys your app serves.

Questions

Can I keep Supabase and host only the frontend on Canner?

Yes. Deploy the app as usual and set VITE_SUPABASE_URL and the anon key (or the NEXT_PUBLIC_ equivalents) as environment variables before the build. Nothing else changes.

Will my users have to reset their passwords?

With an auth library that verifies bcrypt hashes, no: Supabase stores bcrypt hashes and they can be carried over. With Canner Auth, there are no passwords; each user enrols a passkey once from an emailed link.

Does Canner Postgres support Row Level Security?

Yes, it is ordinary Postgres. What it lacks is Supabase’s auth.uid() function and the anon and authenticated roles, so policies written for Supabase need rewriting or replacing with checks in your server routes.

Can I export my data from Lovable Cloud?

Lovable says to export the database and download your storage files; it does not move a project off its built-in backend in one step. Once you have the export, the steps on this page apply.

Does migrate-in work straight from Supabase?

It connects to any Postgres it can reach and copies the whole database into an empty one. A Supabase database often contains objects that only exist on Supabase; if the copy stops on one, dump only the public schema as shown above.

Move the parts that make sense.

Every project comes with Postgres and a private bucket. Start free, move the data, and keep Supabase for whatever isn’t worth rewriting.