Overview
Supabase is a unified platform built from multiple open-source components that work together seamlessly. Each component is independently powerful, but when combined, they provide a complete backend solution.
This architecture applies to both the hosted platform and self-hosted deployments. The core components remain the same.
Core Components
PostgreSQL Database
At the heart of Supabase is PostgreSQL - the world’s most advanced open-source relational database.
Features
ACID compliance for data integrity
Advanced data types (JSON, arrays, ranges)
Full-text search
Geospatial queries with PostGIS
Powerful indexing and query optimization
Extensions
pgvector for AI/embeddings
pg_cron for scheduled jobs
PostGIS for location data
pg_stat_statements for query analysis
And 50+ more extensions
Why PostgreSQL?
PostgreSQL has over 30 years of active development and is trusted by organizations worldwide for:
Reliability and data integrity
Standards compliance
Extensibility
Active community and ecosystem
Battle-tested performance at scale
Example: Advanced Data Types
-- JSON columns for flexible schemas
CREATE TABLE products (
id BIGINT PRIMARY KEY ,
name TEXT ,
metadata JSONB, -- Fast JSON queries
tags TEXT [], -- Array of tags
price_range NUMRANGE -- Price ranges
);
-- Query JSON fields directly
SELECT * FROM products
WHERE metadata ->> 'category' = 'electronics'
AND tags @ > ARRAY ['featured'];
PostgREST
PostgREST automatically generates a RESTful API from your PostgreSQL database schema.
How it works:
PostgREST introspects your database schema
Creates REST endpoints for each table and view
Translates HTTP requests to SQL queries
Respects Row Level Security policies
Request Flow:
Example: Automatic API Generation
-- Create a table
CREATE TABLE articles (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY ,
title TEXT ,
content TEXT ,
published BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW ()
);
PostgREST automatically creates these endpoints:
GET /articles
GET /articles?id=eq.1
POST /articles
PATCH /articles?id=eq.1
DELETE /articles?id=eq.1
# List all articles
curl 'https://your-project.supabase.co/rest/v1/articles' \
-H "apikey: your-anon-key"
Advanced Queries:
PostgREST supports complex queries through URL parameters:
// Filter, sort, and paginate
const { data } = await supabase
. from ( 'articles' )
. select ( 'id, title, author:profiles(name, avatar)' )
. eq ( 'published' , true )
. ilike ( 'title' , '%supabase%' )
. order ( 'created_at' , { ascending: false })
. range ( 0 , 9 ) // Pagination
// Translates to efficient SQL with joins
GoTrue (Authentication)
GoTrue is a JWT-based authentication server that manages users and issues access tokens.
Authentication Flow:
Key Features:
Multiple Auth Methods
Security Features
User Management
Email/Password - Traditional authentication
Magic Links - Passwordless email login
Phone/SMS - Mobile-first authentication
Social OAuth - Google, GitHub, GitLab, Azure, Facebook, Twitter, Discord, and more
SAML SSO - Enterprise single sign-on (Enterprise plan)
JWT tokens - Secure, stateless authentication
Refresh tokens - Long-lived sessions with automatic renewal
Email confirmation - Verify email addresses
Password recovery - Secure reset flows
Rate limiting - Protection against brute force
Multi-factor auth - TOTP-based 2FA
User metadata storage
Custom claims for authorization
Admin API for user management
Hooks for custom logic
Email templates customization
JWT Structure:
When a user signs in, they receive a JWT token:
{
"aud" : "authenticated" ,
"exp" : 1234567890 ,
"sub" : "user-uuid-here" ,
"email" : "user@example.com" ,
"role" : "authenticated" ,
"user_metadata" : {
"full_name" : "John Doe"
}
}
This token is sent with every request, allowing PostgreSQL RLS policies to enforce user-specific access control.
Example: Row Level Security with Auth
-- Only authenticated users can read profiles
CREATE POLICY "Profiles are viewable by authenticated users"
ON profiles FOR SELECT
TO authenticated
USING (true);
-- Users can only update their own profile
CREATE POLICY "Users can update own profile"
ON profiles FOR UPDATE
TO authenticated
USING ( auth . uid () = id)
WITH CHECK ( auth . uid () = id);
-- Custom role-based access
CREATE POLICY "Admins can delete any profile"
ON profiles FOR DELETE
TO authenticated
USING (
auth . jwt () ->> 'role' = 'admin'
);
Realtime
Realtime is an Elixir server that broadcasts database changes and enables presence and broadcast features.
Three Modes of Operation:
Database Changes
Presence
Broadcast
Listen to INSERT, UPDATE, and DELETE operations: // Subscribe to all changes on a table
const channel = supabase
. channel ( 'messages' )
. on (
'postgres_changes' ,
{
event: '*' ,
schema: 'public' ,
table: 'messages'
},
( payload ) => {
console . log ( 'Change received!' , payload )
}
)
. subscribe ()
How it works:
PostgreSQL publishes WAL (Write-Ahead Log) changes
Realtime server listens to the replication slot
Filters changes based on RLS policies
Broadcasts to subscribed clients via WebSockets
Realtime respects Row Level Security! Users only receive updates for rows they have access to.
Track which users are online: const channel = supabase . channel ( 'room1' )
// Send presence data
channel
. on ( 'presence' , { event: 'sync' }, () => {
const state = channel . presenceState ()
console . log ( 'Online users:' , state )
})
. subscribe ( async ( status ) => {
if ( status === 'SUBSCRIBED' ) {
await channel . track ({
user_id: userId ,
online_at: new Date (). toISOString (),
})
}
})
Use cases:
Online user indicators
Collaborative editing cursors
“User is typing…” indicators
Active session tracking
Send messages between clients: const channel = supabase . channel ( 'game-room' )
// Listen for messages
channel
. on ( 'broadcast' , { event: 'move' }, ( payload ) => {
console . log ( 'Player moved:' , payload )
})
. subscribe ()
// Send a message
channel . send ({
type: 'broadcast' ,
event: 'move' ,
payload: { x: 100 , y: 200 }
})
Use cases:
Multiplayer games
Chat applications
Collaborative whiteboards
Live cursors and selections
Architecture:
PostgreSQL WAL
↓
Realtime Server (Elixir)
↓
WebSocket Connections
↓
Client Applications
Storage
Storage provides S3-compatible object storage with PostgreSQL-based permissions.
Features:
Storage Capabilities
Large file uploads (up to 5GB per file)
Resumable uploads
Automatic image optimization
CDN distribution
Signed URLs for private files
Security
Row Level Security for file access
Bucket-level policies
File size and type restrictions
Virus scanning (Enterprise)
Example: Image Upload with RLS
// Create a storage bucket
const { data , error } = await supabase
. storage
. createBucket ( 'avatars' , {
public: false ,
fileSizeLimit: 1024 * 1024 * 2 // 2MB
})
// Upload a file
const file = event . target . files [ 0 ]
const { data , error } = await supabase
. storage
. from ( 'avatars' )
. upload ( ` ${ userId } / ${ file . name } ` , file )
// Get public URL (for public buckets)
const { data } = supabase
. storage
. from ( 'avatars' )
. getPublicUrl ( ` ${ userId } / ${ file . name } ` )
// Get signed URL (for private buckets)
const { data , error } = await supabase
. storage
. from ( 'avatars' )
. createSignedUrl ( ` ${ userId } / ${ file . name } ` , 60 ) // 60 seconds
Storage Policies:
-- Allow users to upload their own avatars
CREATE POLICY "Users can upload own avatar"
ON storage . objects FOR INSERT
TO authenticated
WITH CHECK (
bucket_id = 'avatars' AND
( storage . foldername ( name ))[1] = auth . uid ():: text
);
-- Allow users to view all avatars
CREATE POLICY "Avatars are publicly accessible"
ON storage . objects FOR SELECT
TO public
USING (bucket_id = 'avatars' );
-- Allow users to delete their own avatars
CREATE POLICY "Users can delete own avatar"
ON storage . objects FOR DELETE
TO authenticated
USING (
bucket_id = 'avatars' AND
( storage . foldername ( name ))[1] = auth . uid ():: text
);
Image Transformation:
Automatic image optimization on-the-fly:
// Resize and optimize
const url = supabase
. storage
. from ( 'avatars' )
. getPublicUrl ( 'user.jpg' , {
transform: {
width: 200 ,
height: 200 ,
resize: 'cover' ,
quality: 80
}
})
Edge Functions
Edge Functions are server-side TypeScript functions that run on Deno at the edge, close to your users.
Key Characteristics:
TypeScript/JavaScript - Familiar language and syntax
Deno runtime - Secure by default, modern APIs
Global distribution - Deploy to regions worldwide
Fast cold starts - Minimal latency
HTTP triggers - Invoke via HTTP requests
Cron triggers - Schedule periodic execution
Example: Send Welcome Email
// supabase/functions/send-welcome-email/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
const RESEND_API_KEY = Deno . env . get ( 'RESEND_API_KEY' )
serve ( async ( req ) => {
try {
// Get user from auth header
const authHeader = req . headers . get ( 'Authorization' ) !
const supabase = createClient (
Deno . env . get ( 'SUPABASE_URL' ) ?? '' ,
Deno . env . get ( 'SUPABASE_ANON_KEY' ) ?? '' ,
{ global: { headers: { Authorization: authHeader } } }
)
const { data : { user } } = await supabase . auth . getUser ()
// Send email via Resend
const res = await fetch ( 'https://api.resend.com/emails' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ RESEND_API_KEY } `
},
body: JSON . stringify ({
from: 'noreply@yourapp.com' ,
to: user . email ,
subject: 'Welcome to Our App!' ,
html: `<h1>Welcome ${ user . email } !</h1>`
})
})
const data = await res . json ()
return new Response (
JSON . stringify ( data ),
{ headers: { 'Content-Type' : 'application/json' } }
)
} catch ( error ) {
return new Response (
JSON . stringify ({ error: error . message }),
{ status: 500 , headers: { 'Content-Type' : 'application/json' } }
)
}
})
Deploy and invoke:
# Deploy
supabase functions deploy send-welcome-email
# Invoke from client
const { data, error } = await supabase.functions.invoke ( 'send-welcome-email' )
Use Cases:
Send emails or notifications
Process payments with Stripe
Generate PDFs or images
Call third-party APIs
Complex validation logic
Data aggregation and reporting
Webhooks from external services
pg_graphql
pg_graphql is a PostgreSQL extension that exposes a GraphQL API.
Example: GraphQL Queries
// Query with the JavaScript client
const { data , error } = await supabase
. graphql
. query ( `
query GetPosts {
postsCollection {
edges {
node {
id
title
author {
name
}
comments {
edges {
node {
content
}
}
}
}
}
}
}
` )
GraphQL is automatically generated from your database schema and respects Row Level Security.
Kong API Gateway
Kong sits in front of all services, providing:
Request routing - Direct requests to appropriate services
Rate limiting - Protect against abuse
API key validation - Verify authentication
CORS handling - Cross-origin request management
Request/response transformation - Modify requests as needed
Request Flow:
Client Request
↓
Kong Gateway
├→ /rest/v1/* → PostgREST
├→ /auth/v1/* → GoTrue
├→ /storage/v1/* → Storage API
├→ /realtime/v1/* → Realtime Server
└→ /functions/v1/* → Edge Functions
postgres-meta
postgres-meta provides a RESTful API for managing PostgreSQL:
Fetch tables, columns, and relationships
Create and modify schemas
Manage roles and permissions
Run queries
View database statistics
This powers the Supabase Studio interface.
Studio Dashboard
Supabase Studio is the web-based dashboard that provides:
Table Editor Visual interface to browse and edit data, manage relationships, and view table schemas
SQL Editor Write and execute SQL queries with autocomplete and saved snippets
Auth Management Manage users, configure providers, and customize email templates
Storage Browser Browse buckets, upload files, and manage storage policies
API Documentation Auto-generated API documentation based on your schema
Database Monitoring View query performance, connection pools, and resource usage
Request Lifecycle
Let’s trace a typical request through the Supabase stack:
Client makes request
User application sends a request to query todos: const { data } = await supabase
. from ( 'todos' )
. select ( '*' )
. eq ( 'user_id' , userId )
Kong receives request
Kong validates the API key and routes to PostgREST at /rest/v1/todos
PostgREST processes
Parses the request into SQL
Extracts JWT from headers
Sets PostgreSQL session variables (request.jwt.claims)
PostgreSQL executes query
Runs the SQL query
Evaluates Row Level Security policies using JWT claims
Returns only rows the user has access to
SELECT * FROM todos
WHERE user_id = $ 1
AND ( -- RLS policy check
auth . uid () = user_id
)
Response returned
PostgreSQL returns filtered results
PostgREST formats as JSON
Kong sends response to client
Total round trip: ~50-100ms
Deployment Architecture
When using supabase.com:
Global CDN (Cloudflare)
↓
Load Balancer
↓
┌─────────────────────────┐
│ Your Project │
│ ┌──────────────────┐ │
│ │ Kong Gateway │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌────────┴─────────┐ │
│ │ Service Layer │ │
│ │ • PostgREST │ │
│ │ • GoTrue │ │
│ │ • Realtime │ │
│ │ • Storage │ │
│ │ • Functions │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌────────┴─────────┐ │
│ │ PostgreSQL │ │
│ │ (Dedicated) │ │
│ └──────────────────┘ │
└─────────────────────────┘
Benefits:
Automatic scaling
Global distribution
Managed backups
Monitoring and alerting
No operational overhead
Self-Hosted
Using Docker Compose:
services :
kong :
image : kong:latest
ports :
- "8000:8000"
postgres :
image : supabase/postgres:latest
volumes :
- postgres-data:/var/lib/postgresql/data
auth :
image : supabase/gotrue:latest
rest :
image : postgrest/postgrest:latest
realtime :
image : supabase/realtime:latest
storage :
image : supabase/storage-api:latest
studio :
image : supabase/studio:latest
ports :
- "3000:3000"
Benefits:
Full control
Deploy anywhere
No vendor lock-in
Custom configurations
Security Architecture
Multi-Layer Security
Network Layer
API Layer
Database Layer
Application Layer
TLS/SSL - All traffic encrypted in transit
DDoS protection - Cloudflare protection on hosted platform
Network isolation - Services in private networks
API keys - Required for all requests
JWT validation - Signed tokens verified
Rate limiting - Protection against abuse
CORS policies - Restrict allowed origins
Row Level Security - Fine-grained access control
SSL connections - Encrypted database connections
Database roles - Principle of least privilege
Audit logging - Track all database operations
Email verification - Confirm user identities
Password policies - Enforce strong passwords
MFA support - Two-factor authentication
Session management - Automatic token refresh
API Keys
Supabase provides two main keys:
anon (public) key
service_role key
Safe to use in browsers and mobile apps
Has limited permissions
Used with user JWT for authenticated requests
RLS policies protect data
const supabase = createClient ( url , ANON_KEY )
Never expose in client code
Bypasses Row Level Security
Use only in secure server environments
Full database access
// Server-side only!
const supabase = createClient ( url , SERVICE_ROLE_KEY )
Critical: Never commit service_role keys to version control or use them in client applications. This key has unrestricted access to your database.
Scalability
Supabase components are designed to scale:
Horizontal Scaling
PostgREST - Stateless, can run multiple instances
GoTrue - Scales horizontally with load balancing
Realtime - Distributed across multiple nodes
Storage - S3-compatible, infinitely scalable
Edge Functions - Automatically scaled and distributed
Database Scaling
Vertical Scaling
Read Replicas
Connection Pooling
Increase compute resources:
More CPU cores
More RAM
Faster storage (NVMe SSDs)
Hosted platform supports up to:
64 CPU cores
256 GB RAM
Dedicated resources
Distribute read load:
Create read-only replicas
Route read queries to replicas
Keep write queries on primary
Automatic failover
Efficient connection management:
PgBouncer for connection pooling
Supavisor for advanced pooling
Handle thousands of connections
Minimal overhead
Monitoring and Observability
Built-in Monitoring
Supabase provides comprehensive monitoring:
Query Performance - Slow query logs and analysis
Resource Usage - CPU, memory, disk, and network
API Analytics - Request rates, response times, errors
Realtime Connections - Active connections and channels
Storage Metrics - Bandwidth and storage usage
Logging
Collect logs from all components:
PostgreSQL logs - Query logs, error logs
API logs - Request/response logs
Edge Function logs - Console output and errors
Auth logs - Sign-in attempts and failures
Hosted platform integrates with:
Logflare for log management
Webhook destinations
Custom integrations
Next Steps
Now that you understand Supabase architecture:
Database Guide Deep dive into PostgreSQL features and best practices
Auth Guide Learn advanced authentication patterns
Realtime Guide Build real-time collaborative features
Self-Hosting Deploy Supabase on your infrastructure