← All playbooks
PLAYBOOKDevelopment2 min read

How to Build a Better Sovereign Supabase for Your Needs

For engineers who want Supabase's primitives without its ceiling — and want to shape them.

Who this is for: engineers who want Supabase's primitives, minus the ceiling, plus the ability to shape them to the job.

Supabase made a smart bet: Postgres plus auth plus storage plus realtime is most of what an app needs. The limitation is that it's their assembly, hosted on their terms. Here's how to build the same shape as services you own — and bend where Supabase can't.

The recipe

  1. Scaffold. kilter init sovereign-supabase.
  2. Compose the substrate in kilter.yaml: postgres (your data plane), ory (Kratos for identity, Keto for permissions), garage (S3-compatible storage), typesense (search), temporal (background jobs and realtime-style fan-out).
  3. Schema as migrations, isolation as RLS. Enable Row-Level Security and write your policies once; Postgres enforces tenant isolation on every query, for every client, forever.
  4. Wire auth once. Ory issues the tokens; your API trusts the JWT; RLS reads the claims. No bespoke session or password code to own.
  5. Local parity. kilter up runs the whole stack against the same images prod runs — a green light locally is a real signal, not a sandbox.
  6. Ship. kilter deploy --bootstrap on first deploy provisions the env, runs the initial migration and seed, and returns only once workloads are healthy. You land in production, Org Only (Pangolin + OIDC).
  7. Go live. Hit Promote to open external access and grant production data access through the promotion workflow.
~/sovereign-supabase — zsh
$ kilter init sovereign-supabase
$ kilter up # Postgres + Ory + storage + search, local
$ kilter deploy --bootstrap # provision, migrate, seed, block until healthy