Supabase Architecture

Published on: 08 November 2025

Tags: #supabase #database


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

Share this post

Share on X  •  Share on LinkedIn  •  Share via Email