Running self-hosted Supabase means managing over a dozen Docker containers, each with different resource demands. Without proper tuning, Kong might consume 2GB of RAM while Auth barely uses 10MB. Your VPS could be starving critical services while others sit idle with excess resources.
This guide walks you through optimizing each Supabase container for production workloads—covering memory limits, CPU allocation, and the specific tuning each service needs.
Understanding Supabase's Container Architecture
Before tuning, you need to understand what you're running. A standard self-hosted Supabase deployment includes:
- supabase-db: PostgreSQL database (the core)
- supabase-rest: PostgREST API server
- supabase-auth: GoTrue authentication service
- supabase-realtime: Phoenix-based WebSocket server
- supabase-storage: File storage API
- supabase-kong: API gateway (often the memory hog)
- supabase-studio: Admin dashboard
- supabase-meta: Metadata service
- supabase-analytics: Logflare analytics (optional as of June 2026)
- supabase-vector: Log collection (optional)
- supabase-edge-functions: Deno runtime
Each service has fundamentally different resource characteristics. PostgreSQL wants RAM for shared buffers. Realtime scales with WebSocket connections. Kong can balloon without limits. Understanding these patterns is essential for effective tuning.
Baseline Resource Requirements
According to community discussions and production deployments, here's typical memory usage for an idle Supabase stack:
| Container | Typical Memory | CPU Pattern |
|---|---|---|
| supabase-db | 350-500MB | Spiky under queries |
| supabase-kong | 200MB-2.5GB | Consistent |
| supabase-analytics | 400-600MB | Moderate |
| supabase-realtime | 150-300MB | Scales with connections |
| supabase-rest | 80-150MB | Scales with requests |
| supabase-studio | 60-100MB | Low |
| supabase-storage | 30-50MB | Low |
| supabase-auth | 8-20MB | Low |
| supabase-meta | 40-70MB | Low |
| supabase-edge-functions | 20-50MB | Scales with invocations |
The total baseline sits around 1.5-4GB depending on configuration. For production, plan for at least 4GB RAM with headroom for spikes.
Setting Docker Resource Limits
Docker Compose supports resource limits through the deploy key. Add these to your docker-compose.yml:
services:
db:
image: supabase/postgres:15.1.1.78
deploy:
resources:
limits:
memory: 1G
cpus: '2.0'
reservations:
memory: 512M
cpus: '0.5'
Key concepts:
limits: Hard caps—container gets killed if exceededreservations: Guaranteed minimum resourcesmemory: RAM limit (supports K, M, G suffixes)cpus: CPU cores (1.0 = one full core)
For limits to work with docker compose up, you need to either:
- Use Docker Swarm mode (
docker stack deploy) - Or add
--compatibilityflag:docker compose --compatibility up -d
Service-by-Service Tuning Guide
PostgreSQL (supabase-db)
PostgreSQL is where most tuning effort pays off. The container's memory usage is governed by PostgreSQL's internal configuration, not just Docker limits.
db:
deploy:
resources:
limits:
memory: 2G
cpus: '2.0'
reservations:
memory: 1G
cpus: '1.0'
environment:
- POSTGRES_INITDB_ARGS=--data-checksums
Inside the container, tune these PostgreSQL parameters via environment variables or by modifying the configuration:
shared_buffers = 512MB # 25% of available RAM effective_cache_size = 1536MB # 75% of available RAM work_mem = 16MB # Per-operation memory maintenance_work_mem = 128MB # For VACUUM, CREATE INDEX max_connections = 100 # Adjust based on pool size
For detailed PostgreSQL tuning, see our PostgreSQL performance tuning guide.
Kong API Gateway (supabase-kong)
Kong is often the biggest memory consumer. It loads all routes and plugins into memory, and without limits, it can grow unbounded.
kong:
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.25'
environment:
- KONG_MEM_CACHE_SIZE=64m
- KONG_NGINX_WORKER_PROCESSES=2
Kong-specific optimizations:
- Reduce
nginx_worker_processesfrom auto to a fixed number - Set
mem_cache_sizeexplicitly rather than letting it auto-scale - Consider replacing Kong with Caddy or Traefik if memory is critical—some users report saving hundreds of MB of RAM
Realtime Server
Memory scales linearly with WebSocket connections. Plan for roughly 1KB per connection plus base overhead.
realtime:
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 128M
cpus: '0.25'
environment:
- MAX_HEADER_LENGTH=8192
- REPLICATION_MODE=RLS
For applications with thousands of concurrent connections, see our Realtime configuration guide.
PostgREST (supabase-rest)
PostgREST maintains a connection pool to PostgreSQL. Memory usage correlates with concurrent API requests.
rest:
deploy:
resources:
limits:
memory: 256M
cpus: '1.0'
reservations:
memory: 64M
cpus: '0.25'
environment:
- PGRST_DB_POOL=20
- PGRST_DB_POOL_ACQUISITION_TIMEOUT=10
Lower PGRST_DB_POOL if you're running into connection limits. Each pool connection consumes database resources.
Auth Service (GoTrue)
Auth is lightweight but handles critical authentication flows. Don't starve it.
auth:
deploy:
resources:
limits:
memory: 128M
cpus: '0.5'
reservations:
memory: 32M
cpus: '0.1'
Storage API
Memory usage depends on concurrent uploads and file sizes. For large file uploads, allocate more.
storage:
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
reservations:
memory: 64M
cpus: '0.1'
environment:
- FILE_SIZE_LIMIT=52428800
- UPLOAD_TEMP_PATH=/tmp/uploads
Analytics and Vector (Optional)
As of June 2026, these services are opt-in. If you don't need the Logs Explorer in Studio, skip them entirely:
# Remove or comment out analytics and vector services # analytics: # ... # vector: # ...
This alone can save 500MB-1GB of RAM.
Studio Dashboard
Studio is a Next.js application. It's not needed for production API workloads—consider running it separately or only during development.
studio:
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
reservations:
memory: 64M
cpus: '0.1'
Complete Production Configuration
Here's a consolidated example for a 4GB VPS:
version: '3.8'
services:
db:
deploy:
resources:
limits:
memory: 1536M
cpus: '2.0'
reservations:
memory: 768M
# ... rest of db config
kong:
deploy:
resources:
limits:
memory: 384M
cpus: '0.5'
reservations:
memory: 192M
# ... rest of kong config
rest:
deploy:
resources:
limits:
memory: 192M
cpus: '0.5'
reservations:
memory: 64M
# ... rest config
realtime:
deploy:
resources:
limits:
memory: 384M
cpus: '0.5'
reservations:
memory: 128M
# ... realtime config
auth:
deploy:
resources:
limits:
memory: 96M
cpus: '0.25'
reservations:
memory: 32M
# ... auth config
storage:
deploy:
resources:
limits:
memory: 192M
cpus: '0.25'
reservations:
memory: 48M
# ... storage config
studio:
deploy:
resources:
limits:
memory: 192M
cpus: '0.25'
reservations:
memory: 64M
# ... studio config
meta:
deploy:
resources:
limits:
memory: 96M
cpus: '0.25'
reservations:
memory: 32M
# ... meta config
This allocates roughly 3GB to containers, leaving 1GB for the OS, Docker daemon, and spikes.
Monitoring Resource Usage
After deploying limits, monitor actual usage:
# Real-time container stats
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"
# Check for OOM kills
docker inspect --format='{{.State.OOMKilled}}' <container_name>
# View resource limits
docker inspect --format='{{.HostConfig.Memory}}' <container_name>
For production monitoring, integrate with Prometheus and Grafana.
Warning Signs and Troubleshooting
Container keeps restarting:
- Check
docker logs <container>for OOM messages - Increase memory limit or investigate memory leaks
- Verify reservations don't exceed host capacity
Swap usage climbing:
- Add more RAM or reduce container limits
- Swap above 70% indicates resource starvation
Kong consuming excessive memory:
- Set explicit
KONG_MEM_CACHE_SIZE - Reduce worker processes
- Consider alternative reverse proxies
Database performance degraded:
- Increase
shared_buffers - Check connection pooling configuration
- Monitor query performance with
EXPLAIN ANALYZE
When to Scale Up
Resource limits help on constrained hardware, but there's a floor. If you're consistently hitting limits across multiple services, it's time to:
- Add RAM first—most Supabase services are memory-bound
- Add CPU second—only matters under high concurrent load
- Consider horizontal scaling for Realtime if you have thousands of WebSocket connections
For VPS recommendations, see our guide on best VPS providers for self-hosted Supabase.
Conclusion
Proper container resource tuning transforms a struggling self-hosted Supabase into a stable production system. Start with the baseline recommendations, monitor actual usage, and adjust based on your workload patterns.
The key insights:
- PostgreSQL needs the most memory—don't skimp
- Kong can be a memory hog—set explicit limits
- Analytics/Vector are optional as of June 2026—skip them to save resources
- Always leave headroom for the OS and spikes
- Monitor before and after changes to validate improvements
With Supascale, you get a streamlined management interface that handles deployment complexity, letting you focus on building rather than container orchestration. But whether you manage containers manually or use a platform, understanding these resource patterns helps you make informed scaling decisions.
