Skip to content
Agent Month

Supabase production hardening

Last verified: June 2026· playbook

Supabase production hardening
ImageFile:Rear of rack at NERSC data center - closeup.jpgbyDerrick Coetzee from Berkeley, CA, USACC0 1.0tinted

RLS first: the single most common production-readiness miss

Supabase Row Level Security is your primary security boundary. If it's wrong, everything is exposed. The default state of an AI-generated Supabase project is "RLS off on the user-facing tables" because the prototype doesn't need it — there's only one user, and they're the admin.

The first week of any Supabase production hardening is making RLS correct. The pattern:

  1. Inventory every table. For each, mark it as "user-facing" or "internal/system".
  2. For every user-facing table: turn RLS on. alter table foo enable row level security;
  3. Write a policy per access pattern. create policy "users read own rows" on foo for select using (auth.uid() = user_id);
  4. Test every policy. Open the Supabase client with a stolen JWT (the test should fail). Open with no JWT (the test should fail). Open with a different user's JWT (the test should fail). This is the test you can't skip.
  5. Audit the policies quarterly. The next person to add a table will turn RLS off by default. The audit catches it.

The single highest-leverage work in any Supabase project. Everything else is downstream.

Auth hardening: SSO, MFA, RBAC, audit logs

The prototype usually has "basic email + password" auth with a dev test user. Production needs SSO, MFA, RBAC, and audit logs.

If you're using Supabase Auth:

  • Replace the dev test user with a real signup flow. Email + password with proper validation, password reset, account recovery, email verification.
  • Add SSO. SAML or OIDC. Most enterprise customers require it. Clerk, WorkOS, or Supabase's own SSO (Teams plan) work.
  • Add MFA. SMS is the floor; TOTP (authenticator app) is the bar; passkeys are the future. Most teams skip MFA in the prototype and regret it in the security review.
  • Add RBAC. Default role is authenticated; add admin and owner with a documented role hierarchy in RLS policies.
  • Wire audit logs. Every login, every role change, every permission grant. The logs are queryable; the security team can answer "who accessed X in the last 30 days" in seconds.

The rule: every auth-related change is a policy change, not a code change. Policies are auditable; code is not.

Secrets + backups + the data-exit boundary

Secrets and backups are the unglamorous half of production hardening. They are also the half that bites you when the auditor asks for an incident report.

Secrets:

  • No secrets in the client. The Supabase anon key is fine in the client (it's RLS that protects the data); every other secret — service role key, third-party API keys, webhooks — goes through a secrets manager (1Password, Doppler, Vault, Supabase Vault).
  • Rotate on a schedule. Service role keys quarterly; third-party API keys annually or on a security event.
  • Audit who has access. The principle of least privilege applies to your team, not just the application.

Backups:

  • Automated daily. Point-in-time recovery enabled (Supabase has this on Pro plan and above).
  • Test the restore. "We have backups" is not a backup until you've restored from one. Quarterly restore drill.
  • Encrypt the backups at rest. Supabase does this by default on Pro+; document the encryption in the compliance matrix.
  • Define the RPO and RTO. Recovery Point Objective: how much data can you afford to lose? Recovery Time Objective: how fast must you be back? These are the SLA numbers the auditor asks for.

The data-exit boundary: every query, every Edge Function call, every webhook — anything that sends data out of the Supabase project — is logged. The compliance evidence trail is "what data left, when, to whom, why".

Observability: per-route cost, latency, error rate

Observability in the Supabase context is three things: per-route cost, per-route latency, per-route error rate. The first one is the one most teams miss.

Cost:

  • Per-route: Supabase bills by row reads, row writes, function invocations, storage, egress. Without per-route cost, you can't see which route is driving 80% of the bill.
  • Per-team: production Supabase bills grow fast. Per-team budgets surface the spike before finance does.
  • Per-environment: dev should be 1–5% of production. If dev is 30% of production, you have an RLS-off test hitting production data.

Latency:

  • Per-route p50, p95, p99. The p50 is what users feel; the p99 is what your on-call feels.
  • Per-environment. Dev p50 should be within 2x of production; if it's 10x slower, your dev environment is the bug.

Error rate:

  • Per-route error rate, with a SLO target (e.g. "p99 < 500ms, error rate < 0.1%").
  • Alerting on SLO breach, not raw metrics. Page the on-call when the SLO is in danger, not when the database CPU is high.

The observability stack: same tool the rest of production uses (Datadog, Grafana + Prometheus, Sentry). Not a Supabase-specific tab. The team's on-call is not a Supabase expert; the on-call's tools need to surface the same context regardless of where the service lives.

Migrations, not schema push

The AI-generated prototype has "schema push" — the AI wrote a migration once, ran it, and the database moved on. Production has migrations, version-controlled, reversible, with a deploy + rollback story.

The pattern:

  1. Every schema change is a migration file in the repo. supabase/migrations/20250628120000_add_orders_table.sql. Time-stamped. Reversible.
  2. CI runs the migration against a fresh database on every PR. The PR is blocked if the migration fails or if the resulting schema doesn't match the expected state.
  3. Deploy runs the migrations as part of the deploy. Migrations are idempotent (create table if not exists, alter table add column if not exists) so a partial failure is recoverable.
  4. Rollback is a separate migration that undoes the change. Not "drop the column" — the rollback migration that restores the previous state.
  5. Migrations are reviewed. A senior engineer signs off on every migration that touches a user-facing table, drops a column, or changes an index. RLS changes are reviewed by a second senior engineer.

The migrations directory is in the repo, in version control, with the rest of the application. The team can read the schema history the same way they read the code history.

When to migrate off Supabase (and when not to)

When to migrate off Supabase, and when not to. The honest answer is "rarely, and only with a real trigger".

Real triggers (migrate off Supabase):

  • Compliance. You need a BAA with every sub-processor, your data must stay in a specific region, or you need SOC 2 Type II with infrastructure audit access. Supabase's compliance posture doesn't always cover regulated workloads.
  • Scale. You're past the size where a managed Postgres makes sense: large read replicas, complex read-write splitting, or query patterns that need a custom Postgres config.
  • Lock-in. The Supabase-specific features (RLS, Edge Functions, Realtime) are too central to your app and the team is concerned about vendor lock-in.

Not real triggers (don't migrate):

  • "We want to own our infrastructure." Owning infrastructure is expensive; for most teams it's a net loss. The Supabase bill is the cost of not having a Postgres DBA on staff.
  • "Supabase is too expensive." At most production sizes, Supabase is competitive with self-hosted Postgres + a DBA. Run the numbers before you migrate.
  • "The AI-generated Supabase schema is messy." A schema migration is not a platform migration. Clean up the schema, keep the platform.

If you do migrate, the right sequencing is: stand up the new platform in parallel, migrate the data, cut over per service, deprecate the old platform. 8–16 weeks; we have a separate playbook for it.

A 4-week rollout plan

A 4-week rollout for the full hardening pass:

  1. Week 1: RLS + audit. Inventory the tables. Enable RLS on every user-facing table. Write a policy per access pattern. Test every policy against a stolen JWT. Document the result.
  2. Week 2: auth hardening. Real signup flow, SSO, MFA, RBAC, audit logs. Wire the secrets manager. Rotate the service role key.
  3. Week 3: migrations + observability. Every schema change is a migration file. Backups are tested. Per-route cost + latency + error rate are wired into the team's existing observability stack.
  4. Week 4: audit artifact + handoff. Compliance matrix, threat model, restore drill results, RBAC review. Runbook per axis. Named internal owner per axis.

End of week 4: every user-facing table is behind RLS, the auth is SSO + MFA + RBAC + audit, the secrets are in a real manager, the backups are tested, the observability is wired, the compliance matrix is ready for the auditor.

Do this yourself vs hire us

When to do this yourself, when to hire:

Do this yourself if…

  • You have a senior engineer who has shipped RLS policies + SSO + MFA + audit logs in production
  • Your Supabase project is small (&lt;10 tables, single team)
  • You have 6+ weeks before the first enterprise customer needs to pass security review
  • You have a clear list of what production means for your app

Hire us if…

  • Your Supabase project is 30+ tables, multiple services, 10+ engineers
  • You have an enterprise customer signing in 2–6 weeks and their security review is the blocker
  • RLS is off on most tables and you don't have senior RLS expertise in-house
  • You want the same engineers who did the LLM cost work + AI-coding rollout to do the Supabase hardening
  • You want outcome pricing tied to the first enterprise customer's sign-off

Frequently asked questions

What is the single most important Supabase hardening task?

Turn RLS on for every user-facing table, with a policy per access pattern, and test every policy against a stolen JWT. The default state of an AI-generated Supabase project is RLS off; this is the single most common production-readiness miss.

Do I need to migrate off Supabase before going to production?

Almost never. Supabase is a managed Postgres + a managed auth + a managed storage + a managed Edge Functions runtime. For most teams, the right answer is to harden the Supabase in place: RLS, auth, secrets, backups, observability. Migrate off only with a real trigger (compliance, scale, or lock-in).

How is this different from the productionization playbook?

The productionization playbook covers the 12 axes for any AI-generated codebase. The Supabase playbook is the deep-dive on the BaaS axis: RLS, auth, secrets, backups, observability, migrations, and the trigger events for migrating off Supabase. The two playbooks cover the same engagement; the Supabase one is the BaaS-specific chapter.

How long does the hardening take?

A focused 4-week engagement covers the 12-axis rubric end-to-end. Smaller projects (single service, single team) take 2–3 weeks. Larger projects (3+ services, multiple teams, regulated data) take 6–8 weeks.

How is this priced?

Fixed-scope: $20–50k for the 4-week engagement. Outcome-priced: tied to the first enterprise customer's security review sign-off (a percentage of the contract value). Outcome pricing is usually the fastest path through procurement.