Implement enterprise Supabase reference architectures — monorepo layout, multi-tenant RLS,
microservices with cross-project access, framework integration, edge functions, caching,
queue patterns, and audit logging.
Use when designing a new Supabase project from scratch, reviewing project structure for
production readiness, planning multi-tenant isolation, or establishing team architecture standards.
Trigger with phrases like "supabase architecture", "supabase project structure",
"supabase monorepo", "supabase multi-tenant", "supabase reference design",
"how to organize supabase at scale".
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Implement enterprise Supabase reference architectures — monorepo layout, multi-tenant RLS,
microservices with cross-project access, framework integration, edge functions, caching,
queue patterns, and audit logging.
Use when designing a new Supabase project from scratch, reviewing project structure for
production readiness, planning multi-tenant isolation, or establishing team architecture standards.
Trigger with phrases like "supabase architecture", "supabase project structure",
"supabase monorepo", "supabase multi-tenant", "supabase reference design",
"how to organize supabase at scale".
Designed for Claude Code, also compatible with Codex and OpenClaw
Supabase Reference Architecture
Overview
Production Supabase applications need more than a flat lib/supabase.ts file. This skill covers five enterprise architecture patterns: monorepo with shared types, multi-tenant RLS isolation, microservices with separate Supabase projects, framework integration (Next.js / SvelteKit), and operational patterns (edge functions, caching, queues, audit trails). Each pattern stands alone — pick the ones that match your scale.
For the full monorepo directory layout and microservices cross-project access, see Project Structure. For edge functions, caching, queue, and audit trail patterns, see Operational Patterns.
Every app in the monorepo imports from a shared package instead of creating its own client. This guarantees a single source of truth for the URL, keys, and type definitions.
Key detail: The admin client sets autoRefreshToken: false and persistSession: false because server-side code should never store user sessions.
Step 2: Multi-Tenant RLS via JWT Claims
The most scalable Supabase multi-tenant pattern uses a custom JWT claim (org_id) combined with RLS policies. Every table includes an org_id column, and RLS extracts the tenant from the user's JWT — no application-level filtering needed.
-- Migration: 20260101000000_create_tenants.sql-- Tenants tablecreate table public.tenants (
id uuid primary keydefault gen_random_uuid(),
name text not null,
slug text uniquenot null,
plan text default'free'check (plan in ('free', 'pro', 'enterprise')),
created_at timestamptz default now()
);
-- Tenant membershipcreate table public.tenant_members (
tenant_id uuid references public.tenants(id) ondelete cascade,
user_id uuid references auth.users(id) ondelete cascade,
role text default'member'check (role in ('owner', 'admin', 'member', 'viewer')),
primary key (tenant_id, user_id)
);
-- Example tenant-scoped tablecreate table public.projects (
id uuid primary keydefault gen_random_uuid(),
org_id uuid not nullreferences public.tenants(id) ondelete cascade,
name text not null,
created_by uuid references auth.users(id),
created_at timestamptz default now()
);
-- Enable RLS on all tenant-scoped tablesalter table public.projects enable row level security;
-- RLS policy: users can only see rows belonging to their tenant-- The org_id is extracted from the JWT claims set during authenticationcreate policy "Tenant isolation" on public.projects
forallusing (
org_id = (auth.jwt() ->>'org_id')::uuid
);
The tenant-switching function verifies membership before updating the JWT claim:
-- Helper function to set org_id in JWT claims after logincreateor replace function public.set_tenant_claim(tenant_id uuid)
returns void as $$
begin-- Verify user is a member of this tenant
if notexists (
select1from public.tenant_members
where tenant_members.tenant_id = set_tenant_claim.tenant_id
and tenant_members.user_id = auth.uid()
) then
raise exception 'Not a member of tenant %', tenant_id;
end if;
-- Set the custom claim
perform auth.update_user_metadata(
auth.uid(),
jsonb_build_object('org_id', tenant_id)
);
end;
$$ language plpgsql security definer;
Key details for multi-tenant RLS:
auth.jwt() ->> 'org_id' reads a custom claim from the user's JWT — zero application code needed
Every tenant-scoped table must have an org_id column and RLS enabled
Tenant switching requires updating the JWT claim and re-authenticating
For row-level tenant + role permissions, combine org_id with a role lookup
Step 3: Framework Integration (Next.js)
Server components use the service_role key for direct database access. Client components use the anon key with RLS protection.
For performance optimization and indexing strategies, see supabase-performance-tuning. For deployment pipelines and CI integration, see supabase-ci-integration. For security hardening and policy guardrails, see supabase-security-basics.