What Lovable already gives you
Lovable turns a chat prompt into a working React app, and since the launch of Lovable Cloud the backend is no longer an afterthought. Every project gets a fully managed Supabase instance — Postgres, authentication, file storage, and edge functions — provisioned and owned by Lovable. You never see it in a Supabase dashboard and you never touch a connection string. For a prototype, that is genuinely the fastest backend you can get.
So if you just asked Lovable to “save form submissions,” it probably already did, using Lovable Cloud. The honest advice: do not replace that while you are still figuring out the app. The reason to read further is not that Lovable Cloud is bad — it is that it is a closed box.
When you actually need your own backend
Lovable Cloud runs on a Supabase project that Lovable owns, not you. You do not get the service-role key or the database URL, and the project does not appear in your own Supabase account. That is fine until one of these is true:
- A second app, a mobile client, an n8n workflow, or a scheduled job needs to read or write the same data.
- You want the database under your own account and billing — so the backend survives even if you stop using Lovable.
- You want a paper trail you control: your own backups, your own keys, your own export.
At that point you connect a backend you own. Lovable supports connecting your own Supabase project, which is the right call if you are comfortable writing schemas and Row Level Security policies in SQL. If you are not — if you came to Lovable precisely so you would not have to — Cradler is the backend designed for that gap.
Connecting Cradler to a Lovable app, step by step
Four steps. None of them involve SQL.
- 01
Create a Cradler project
Sign up at cradler.ai and create a project. Cradler provisions an isolated PostgreSQL database plus file storage and hands you a gateway URL, a project ID, an anon key, and a service key.
- 02
Add @cradler/sdk to your Lovable code
Open the GitHub repo Lovable syncs your project to, or edit in Lovable directly, and install @cradler/sdk. Put the gateway URL, project ID, and anon key in environment variables.
- 03
Describe the data feature to Lovable in chat
Ask Lovable in plain language to save and read your data through the Cradler client — for example, store waitlist sign-ups or load a list of testimonials.
- 04
Publish — the schema fills itself in
The first write creates the table; a later write with a new field adds the column. There is no migration step, and every Cradler database is backed up daily.
The code Lovable will write
Say you built a coaching landing page in Lovable and want to capture waitlist sign-ups in a database you own. You create one client, then insert and read with it. This is the whole integration:
import { createClient } from "@cradler/sdk";
const cradler = createClient({
url: process.env.NEXT_PUBLIC_CRADLER_URL!,
projectId: process.env.NEXT_PUBLIC_CRADLER_PROJECT_ID!,
apiKey: process.env.NEXT_PUBLIC_CRADLER_ANON_KEY!,
});
// Save a waitlist sign-up. The "signups" table and its
// columns are created on this first call — no migration.
export async function joinWaitlist(email: string, plan: string) {
await cradler.from("signups").insert({
email,
plan,
source: "landing-page",
});
}
// Read the latest sign-ups for an admin view.
export async function recentSignups() {
const { rows } = await cradler
.from("signups")
.select("email", "plan", "createdAt")
.order("createdAt", { desc: true })
.limit(50);
return rows;
}Notice there is no CREATE TABLE anywhere. The first insert() tells Cradler a signups collection exists; it infers the column types from the values (text for the strings) and builds the table. If you later add cradler.from("signups").insert({ email, plan, referredBy }), Cradler runs an ADD COLUMN for referred_by on the fly. Camel case in your code maps to snake case in Postgres automatically.
Adding image uploads
If your Lovable app lets users upload a profile photo or a document, storage is part of the same Cradler project — no separate bucket, no second provider. Upload the file, then save its path in a row:
async function saveProfilePhoto(userId: string, file: File) {
const path = `avatars/${userId}/${file.name}`;
await cradler.storage.upload(path, file, {
contentType: file.type,
});
await cradler
.from("profiles")
.update({ avatarPath: path })
.eq("userId", userId);
}
// Later, get a signed URL to display it.
async function avatarUrl(path: string) {
return cradler.storage.getUrl(path);
}Gotchas worth knowing
The anon key is public.Anything in a client-side Lovable component ships to the browser, so use the anon key there and gate each table's read/insert/update/ delete permissions in the Cradler dashboard. Keep the service key, which bypasses those checks, only in server code.
Type conflicts are rejected, not coerced.If a column emerged as text and you later send a number for it, Cradler returns a clear error rather than silently corrupting the column. Lovable's AI reads that error and corrects the call — usually in the same chat turn.
Destructive changes are deliberate. Cradler adds tables and columns automatically but never renames or drops them on its own. Renaming a field or changing a type is a confirmed action in the dashboard, with a backup — so an off-hand prompt can never delete a column of real data.
Why Cradler suits Lovable builders
Lovable's whole pitch is that you describe an app and the AI builds it. A backend should hold to the same standard. Cradler ships a typed SDK, per-project generated TypeScript types, an llms.txt, and @cradler/mcp, an MCP server — so the AI generating your data code is working from your real schema, not a guess. And because the database is standard PostgreSQL, nothing about it is locked to Cradler if you ever want to take it elsewhere. See the @cradler/sdk package for the full API.