Supabase Authorization and Production Operations

Supabase puts a PostgreSQL database directly behind an auto-generated API, so browsers and mobile apps can query tables with nothing in between but the database's own permissions. That is what makes it fast to build with — and why authorization lives in the database. Every table reachable through the API must be protected by row-level security (RLS) policies and correct grants; a single table without them can expose every row to anyone holding the public API key, which by design ships in every client.

Production readiness goes beyond policies: tested migrations, controlled privileges for functions and views, storage access rules, connection pooling, backups that have actually been restored, and careful handling of the keys that bypass all of it.

TL;DR

Quick Example

Organization-scoped projects: members can read, only admins can update.

A pgTAP test that impersonates a non-admin member and proves both policies:

Core Concepts

Roles and Keys

The publishable key is public by design; security comes from RLS and grants. Secret keys must stay in server-side secrets, be rotatable, and never appear in client bundles, mobile apps, or logs.

Writing Policies

Grants, Functions, and Views

RLS only filters rows; grants decide which tables, columns, and functions the API roles can touch at all. Default privileges in exposed schemas are broad, so harden them:

Storage Policies

Files live in buckets whose access is controlled by RLS policies on storage.objects. Common patterns: private buckets with per-user folders ((storage.foldername(name))[1] = (SELECT auth.uid())::text), size and type limits per bucket, and short-lived signed URLs for downloads. Public buckets are appropriate only for genuinely public assets. See Object Storage and Signed Download URLs.

Production Operations

Migrations

Keep the schema in version control as migrations: create them with supabase migration new, generate diffs from local changes with supabase db diff, test them against a local stack and CI, and apply with supabase db push or a deployment pipeline. Avoid editing production through the dashboard, which creates drift between environments. See Database Migrations.

Connections

Serverless functions and many short-lived clients exhaust PostgreSQL connections quickly. Use the connection pooler (transaction mode) for those workloads, direct connections for migrations and long-lived services, and monitor connection counts. See PostgreSQL Connection Pooling.

Backups and Recovery

Managed projects include daily backups, and point-in-time recovery is available as an add-on for finer recovery points. Also take independent logical backups (for example supabase db dump) for critical data, store them outside the project, and practice restores into a separate project, measuring recovery time. Remember Storage objects need their own backup strategy. See PostgreSQL Backup and Recovery.

Hardening Checklist

Best Practices

Deny by Default

Enable RLS before adding data, start with no policies (no access), and add the narrowest policies each feature needs.

Test Policies Like Code

Write pgTAP tests impersonating anonymous users, members, admins, and users from other tenants, and run them in CI for every migration.

Keep Privileged Work on the Server

Operations that cross tenants or need elevated access belong in server code or Edge Functions using the service role, with their own authorization checks.

Treat Grants and Policies as One Surface

Review table grants, column grants, function EXECUTE grants, view security, and RLS together whenever the schema changes.

Common Mistakes

Forgetting RLS on a New Table

Authorizing on user_metadata

Views That Bypass RLS

FAQ

Is it safe to expose the Supabase publishable key?

Yes, it is designed to be public. Safety depends on row-level security policies and grants that restrict what the anon and authenticated roles can access.

What does the service role key do?

It authenticates as a role that bypasses row-level security. It must only be used in trusted server environments and never shipped to browsers or mobile apps.

How do I test Supabase RLS policies?

Write pgTAP tests that set the role and JWT claims to simulate different users, then assert which rows are visible and which changes succeed. Run them locally and in CI with supabase test db.

Do views respect row-level security?

Not by default: views execute with the owner's privileges. Create them with security_invoker = true so the caller's permissions and policies apply.

How should I back up a Supabase project?

Use the platform's daily backups and point-in-time recovery for the database, keep independent logical dumps of critical data elsewhere, back up Storage objects separately, and test restores regularly.

Related Topics

References