Code gets rewritten constantly. The database schema outlives almost everything else, and migrating it under load is one of the harder things in software. Time spent on schema design pays compounding dividends.
Let the database enforce invariants
Constraints, foreign keys and check rules are not bureaucracy — they're the last line of defense against bad data. Application code has bugs; the database is where correctness should be guaranteed.
RLS is not optional
On Supabase, every table reachable by the client needs Row-Level Security enabled with explicit policies. A table without RLS is a public table.
create table public.documents (
id uuid primary key default gen_random_uuid(),
owner_id uuid not null references auth.users(id) on delete cascade,
title text not null,
created_at timestamptz not null default now()
);
alter table public.documents enable row level security;
create policy "owners read their documents"
on public.documents for select
to authenticated
using (auth.uid() = owner_id);Migrate forward, never edit in place
Every schema change is a migration that's reviewed, versioned and reversible. Editing production schema by hand is how teams lose data.
- Enable RLS on every client-reachable table
- Add indexes for the queries you actually run
- Use foreign keys with explicit on-delete behavior
- Keep migrations small and reversible



