Tools
    ·

    Why I use Supabase

    I use Supabase because I got burned by not using it. Here's the Lovable Cloud story, why ownership matters more than you think, and the RLS silent failure that taught me the most.

    By The Non-Developer Developer

    # Why I use Supabase

    **Slug:** why-i-use-supabase
    **Category:** Tools

    ---

    I use Supabase because I got burned by not using it.

    That's where this story starts. I built my first serious app — a booking marketplace — in Lovable. Lovable managed the database on my behalf through Lovable Cloud. It felt convenient. It was actually a trap.

    When I wanted to move to a proper local development setup, I found out I couldn't directly access my own database. No migration files. No way to query it directly. The schema existed somewhere in Lovable's infrastructure and I had no clean path to extract it. My own product's data architecture was something I couldn't see or touch.

    Supabase is the thing that makes sure that never happens again.

    ---

    ## What Supabase actually is

    Supabase is a backend platform built on PostgreSQL. It gives you a full relational database, authentication, file storage, edge functions, and a real-time system — all in one place, all connected through a clean dashboard and a TypeScript client library that works beautifully with React.

    The key word is PostgreSQL. Not a proprietary document store, not a NoSQL system, not something that only works through a vendor's SDK. Standard SQL, the same database technology that powers most of the internet, with proper support for relationships between tables, foreign keys, complex queries, and row-level security.

    You can query it with psql from your terminal. You can inspect it in the dashboard. You can write and run SQL directly. You own it.

    ---

    ## Why ownership matters more than you think

    The thing that surprised me after getting burned by Lovable Cloud wasn't that the data was locked — it was how long it took me to notice.

    The app was working. Features were being built. Everything looked fine. I just had no idea what was actually in my database, whether my schema made sense, or whether anything was actually being written correctly when it should have been.

    The moment I moved to my own Supabase and connected psql, I discovered three problems I hadn't known existed: tables with row-level security enabled but no write policies (writes were failing silently — success messages showing, data not actually saving), a user profile trigger that wasn't firing correctly for new signups, and a query that was returning empty results because it was reading the user ID from the wrong place.

    None of these showed up as errors. All of them would have caused real problems once the app had real users.

    Psql showed me immediately: `SELECT * FROM profiles;` — empty after creating three test users. The table existed, the auth worked, the data just wasn't there. Claude Code traced the issue to a broken trigger in two minutes once I had the actual database to interrogate.

    Without direct access, I'd have been debugging against symptoms. With it, I could see the problem directly.

    ---

    ## Migration files — the thing nobody sets up until they need them

    This is the second thing the Lovable Cloud experience taught me, and it's the most important operational lesson I've learned.

    When you use Lovable to manage your database, or when you make changes directly in the Supabase dashboard, changes happen without a corresponding migration file. The schema exists in production but nowhere in your codebase.

    Migration files are how you track what your database looks like over time. Every schema change — adding a table, adding a column, changing a constraint — lives in a file that gets committed to git. When you deploy, those files run in order and produce a database that matches exactly what your code expects.

    Without migration files, you're in a situation where:
    - Your AI coding agent thinks the database has column X because that's what it reads in the types file
    - Production has column X, but your local development database doesn't
    - The agent's code works in production but not locally, or works locally but not in staging
    - You spend a day debugging something that would have been impossible if the schema was version-controlled

    The fix is to run `supabase db pull` before you start working with Claude Code or Codex on anything schema-related. That creates a baseline migration from your current Supabase state. Everything from that point goes through migration files and gets deployed through CI — never through the dashboard, never directly from the agent.

    ---

    ## Row-level security — why it matters and why it's hard

    Supabase's row-level security (RLS) is the feature that looks boring until you understand it.

    RLS is authorization at the database layer. Instead of checking in your application code whether a user is allowed to see or modify a record, the database itself enforces those rules. Every query — from your app, from an agent, from a migration script, from a direct psql connection — goes through the same security check.

    The practical consequence: if you forget to add a policy, writes fail silently. No error. Just... nothing saved.

    This is the failure mode that catches almost everyone who's new to Supabase. The success toast fires in the UI. The data isn't there. You check the network tab and the request returned 200. The data still isn't there. You've now spent an hour debugging something that psql would show you in three seconds.

    The lesson I pass on: as soon as you add RLS to a table, immediately add all four policies (SELECT, INSERT, UPDATE, DELETE) for your authenticated users. Check `SELECT tablename, policyname, cmd FROM pg_policies ORDER BY tablename, cmd;` regularly. If a table has RLS but no INSERT policy, users can't save to it.

    Claude Code is excellent at writing these policies once you know what you want. The hard part is knowing they're missing.

    ---

    ## Why not Firebase

    The community has largely settled on this and it matches my experience: Supabase for web apps with relational data, Firebase if you're building a mobile app that needs offline sync.

    For what I build — internal tools, B2B-ish web apps, marketplaces — the relational data model is right. Supabase's PostgreSQL gives me joins, foreign keys, complex queries, and proper data integrity enforcement. Firebase's document store would have me denormalizing data and writing application code to do things the database should handle.

    The pricing model is also better for my use case. Supabase charges for compute and storage, not for individual query operations. Firebase charges per document read and write — a bug that accidentally reads the database too many times becomes a surprise bill. Supabase doesn't work that way.

    ---

    ## The honest picture

    Supabase has a learning curve, mostly around RLS and migrations. Both are concepts that don't exist in most no-code tools, and both can bite you in ways that are non-obvious if you haven't encountered them before.

    The TNDD toolkit includes a CLAUDE.md rules file specifically for database work — it enforces that the agent never modifies migration files directly, never pushes to Supabase from the agent, and flags any task touching the database for explicit plan review before execution.

    But beyond the tooling: get direct access to your database from day one. Run psql against it. Look at what's actually in there after every test. The moment something isn't saving that should be saving, psql will tell you in seconds.

    Ownership and visibility aren't optional. They're what makes everything else reliable.

    ---

    *Part of my full stack: Lovable (UI) + Claude Code + Codex (development) + Supabase (backend) + Vercel (deployment).*

    *The TNDD database rules file for Claude Code is included in the toolkit.*

    *[Download the Toolkit]*