Supabase Architecture
Published on: 08 November 2025
Supabase Architecture Diagram
graph LR
subgraph "Clients"
direction TB
A[Client Libraries]
B[Supabase Studio]
end
subgraph "Gateway & Edge"
direction TB
C[Kong API Gateway]
D[Edge Functions]
end
subgraph "Backend Services"
direction TB
E[GoTrue Auth]
F[PostgREST API]
G[Realtime]
H[Storage Engine]
end
subgraph "Data Layer"
direction TB
I{Postgres Database
The Source of Truth}
J[S3 Object Storage]
end
%% Connections
A --> C
B -- Manages --> I
C --> E & F & G & H & D
E -- "Reads/writes auth schema" --> I
F -- "Generates API from schema" --> I
G -- "Listens for DB changes" --> I
H -- "Manages file metadata" --> I
D -- "Can query the database" --> I
H -- "Stores/Retrieves files" --> J
style I fill:#f9b115,stroke:#333,stroke-width:4px
Supabase Authentication Flow Diagram
sequenceDiagram
participant Client
participant Kong API Gateway
participant GoTrue
participant PostgREST
participant PostgreSQL
alt Authentication: Obtaining a Token
Client->>Kong API Gateway: 1. Sign-up/Login Request
Kong API Gateway->>GoTrue: 2. Forwards to /auth endpoint
GoTrue->>PostgreSQL: 3. Queries/Creates user in auth.users
PostgreSQL-->>GoTrue: 4. Returns user data
GoTrue-->>Client: 5. Issues signed JWT
end
alt Authenticated API Request: Using the Token
Client->>Kong API Gateway: 6. API Request with JWT in header
Kong API Gateway->>PostgREST: 7. Forwards request to API service
PostgREST->>PostgreSQL: 8. Validates JWT and sets transaction role (e.g., SET ROLE authenticated)
note right of PostgreSQL: PostgreSQL now enforces RLS policies
for this specific user and role
PostgreSQL-->>PostgREST: 9. Returns only authorized data
PostgREST-->>Client: 10. Returns data as JSON
end
Supabase Realtime Flow Diagram
sequenceDiagram
participant ClientA as Client A
participant PostgreSQL
participant Realtime Server
participant ClientB as Client B
ClientB->>Realtime Server: 1. Subscribes to 'todos' table changes
Realtime Server-->>ClientB: 2. Subscription confirmed (WebSocket)
ClientA->>PostgreSQL: 3. INSERT INTO todos (task) VALUES ('Finish diagram');
note over PostgreSQL: Logical replication is enabled on the 'todos' table.
PostgreSQL->>Realtime Server: 4. Notifies of change via replication stream
Realtime Server->>Realtime Server: 5. Processes change & checks RLS policies
Realtime Server->>ClientB: 6. Broadcasts new 'todo' as JSON payload
Supabase Storage: File Upload Flow
sequenceDiagram
participant Client
participant Storage Engine
participant PostgreSQL
participant S3 Storage
Client->>Storage Engine: 1. Request to upload 'avatar.png'
Storage Engine->>PostgreSQL: 2. Check RLS policies for 'storage.objects' table
(Can this user INSERT?)
PostgreSQL-->>Storage Engine: 3. Permission granted
Storage Engine-->>Client: 4. Provides a signed URL for direct S3 upload
Client->>S3 Storage: 5. Uploads file directly using the signed URL
S3 Storage-->>Client: 6. Upload successful
Client->>Storage Engine: 7. Notifies that upload is complete
Storage Engine->>PostgreSQL: 8. Creates metadata record in 'storage.objects'
(name, owner, size, etc.)
PostgreSQL-->>Storage Engine: 9. Metadata saved
Storage Engine-->>Client: 10. Returns file URL / Confirmation
Conceptual Diagram: How Row-Level Security Works
graph TD
subgraph "User's Perspective"
A[User with ID 'abc-123'] --> B{User executes a simple query:
SELECT * FROM invoices;};
end
subgraph "PostgreSQL Database Engine"
C[1. Query is received by the database]
D{2. RLS Policy Check
Is there a policy on the 'invoices' table?}
E["POLICY: User can only see their own invoices
USING: auth.uid() = user_id"]
F[3. The policy's condition is dynamically
added to the user's query]
G["4. Final query executed internally:
SELECT * FROM invoices
WHERE auth.uid() = user_id;
"]
end
subgraph "Result"
H[Only the invoices where
user_id = 'abc-123' are returned]
end
B --> C;
C --> D;
D -- Yes --> E;
E --> F;
F --> G;
G --> H;
H --> A;
style A fill:#cde4ff,stroke:#333
style H fill:#d4edda,stroke:#333
style E fill:#fff3cd,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5
style G fill:#f8d7da,stroke:#333,stroke-width:2px