How to Prevent Supabase Overages: Egress, Disk & Compute Cost Guide
Engineering audit: Optimize database egress ($0.09/GB), disk storage auto-scaling cliffs, point-in-time recovery (PITR) add-ons, and connection pooler limits.
Interactive Architecture Budget Estimator
Adjust your operational inputs to calculate unit costs and resource allocations across infrastructure components.
Itemized Architectural Unit Economics
Detailed mathematical cost model comparing raw resource units, provider markups, and optimization strategies.
| Architecture Component | Unit Cost (2026) | Benchmark Throughput / Sizing | Operational Notes & Trade-offs |
|---|---|---|---|
| Supabase Pro Base Plan | $25.00 / month | Includes 8GB database disk, 100GB storage, 250GB bandwidth, 50k MAU auth. | Outstanding baseline value for early startups |
| Database Disk Storage Overage (40GB over) | $5.00 / month | 40GB additional disk storage @ $0.125/GB-mo. | Note: Auto-scaled disk size never automatically scales down! |
| Bandwidth Egress Overage (200GB over) | $18.00 / month | 200GB beyond 250GB included quota @ $0.09/GB. | Can be completely eliminated by routing Storage through Cloudflare |
| Total Expected Monthly Invoice | $48.00 / month | Includes base plan + predictable storage & egress overages. | Cost cap can be enabled in dashboard to prevent overage surprises |
Production Implementation Code
Proxying Supabase Storage via Cloudflare CDN to Eliminate Egress Fees. Deploy directly into your production pipelines.
// cloudflare-worker-supabase-proxy.js - Eliminate Supabase Storage egress fees!
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// Rewrite request to Supabase Storage endpoint
const supabaseUrl = `https://xyz.supabase.co/storage/v1/object/public\${url.pathname}`;
// Cache response at Cloudflare Edge (Tiered Cache = 100% Free egress!)
const cache = caches.default;
let response = await cache.match(request);
if (!response) {
response = await fetch(supabaseUrl, {
headers: { 'Accept': request.headers.get('Accept') }
});
const newHeaders = new Headers(response.headers);
newHeaders.set('Cache-Control', 'public, max-age=604800, s-maxage=604800, immutable');
response = new Response(response.body, { status: response.status, headers: newHeaders });
ctx.waitUntil(cache.put(request, response.clone()));
}
return response;
}
};
Engineering Gotchas & Pitfalls
Critical architectural edge cases documented from real-world high-traffic deployments.
The Disk Auto-Scale Ratchet Mechanism
Supabase auto-scales disk space when you reach 90% capacity to prevent database lockups. However, PostgreSQL disk allocation does not shrink when you delete data. Deleting 20GB of data leaves the provisioned disk at its higher tier, permanently billing for that space until you vacuum and contact support.
Serving Images Directly from Storage Buckets
Serving high-resolution user avatars or document thumbnails directly from `supabase.co/storage` without an edge CDN burns egress at $0.09/GB. 1TB of media downloads adds $90.00 to your bill.
Disabled Spend Caps in Production
Supabase allows you to toggle the 'Spend Cap' on or off. Turning off the spend cap ensures services never go down, but leaves you vulnerable to unbounded usage bills during bot attacks or scraping storms.
Frequently Asked Questions
Practical architectural questions answered with precise mathematical modeling.
Place a free Cloudflare proxy or Cloudflare Worker in front of your Supabase Storage public bucket. Cloudflare caches images, documents, and static assets at edge data centers globally, serving them with unlimited free egress bandwidth.
PostgreSQL marks deleted row space as available for new inserts, but does not release disk blocks back to the underlying operating system filesystem. Reclaiming physical disk space requires running `VACUUM FULL` during maintenance or contacting Supabase support for a disk resize.
When the Spend Cap is enabled, Supabase strictly limits your resources to what is included in the $25/month Pro plan. If you exceed 250GB bandwidth or 100GB storage, additional requests will return errors rather than incurring overage charges.
Related Architecture Guides & Tools
Explore related cost models and interactive simulators on CheckAPICost.
Realtime Quotas, Connection Pool Sizing & Automated Vacuuming
Preventing overage charges on Supabase requires active system administration across three core vector points: Realtime WebSocket connections, PostgreSQL connection pooling exhaustion, and WAL write-ahead log retainage. By default, a burst in active user sessions can exceed Realtime connection quotas (500 concurrent connections on Pro), forcing automated overage charges ($10 per 1,000 concurrent clients). Engineering automated guardrails ensures workloads scale smoothly without crossing billable thresholds.
Monthly Operating Resource Limits: Supabase Pro vs Overages
| System Metric | Pro Plan Included | Overage Price | Failure Mode If Uncapped | Mitigation Technique |
|---|---|---|---|---|
| Realtime Concurrency | 500 active clients | $10 / 1k clients | Socket throttling | SSE / Polling fallback |
| Function Invocations | 2,000,000 calls | $2.00 / 1M calls | Compute billing spike | Edge cache response |
| Database Connections | 60 direct / Supavisor | Server crash | Remaining connection slots | Supavisor Transaction Pool |
| Disk Storage Size | 8 GB baseline | $0.125 / GB-mo | Permanent auto-expansion | pg_cron log cleanup |
Automated PostgreSQL pg_cron Maintenance Script
-- Enable pg_cron extension to automate disk maintenance and purge old audit logs
CREATE EXTENSION IF NOT EXISTS pg_cron;
-- Schedule nightly cleanup of expired auth sessions and audit logs (runs at 03:00 UTC)
SELECT cron.schedule('purge-expired-sessions', '0 3 * * *', $$
DELETE FROM auth.refresh_tokens WHERE revoked = true AND updated_at < NOW() - INTERVAL '7 days';
DELETE FROM public.audit_logs WHERE created_at < NOW() - INTERVAL '30 days';
VACUUM ANALYZE public.audit_logs;
$$);
Operational Defense Rules
- Strict Row Level Security (RLS) Indexes: Queries governed by RLS policies must have indexes on the evaluated columns (e.g. `user_id`, `org_id`). Missing indexes force full sequential table scans, spiking CPU utilization and triggering compute upgrades.
- Disconnect Idle WebSockets: Implement a client-side heartbeat timeout on Supabase Realtime subscriptions. Inactive browser tabs in the background should disconnect their WebSocket channel after 15 minutes of user inactivity.
Engineering Q&A: Supabase Defense Architecture
How does Supavisor prevent connection exhaustion on Supabase?
Supavisor acts as an actor-based proxy running on port 6543. It multiplexes thousands of incoming client requests over a fixed pool of 15-25 physical PostgreSQL connections, shielding the database process table from crashing under serverless connection spikes.
What happens if the Spend Cap is disabled on Supabase Pro?
With Spend Cap disabled, your project automatically consumes additional resources beyond plan quotas (e.g. pay-as-you-go bandwidth and MAUs). While this guarantees 100% uptime without service cutoff, unexpected traffic surges or scrapers can produce high invoices if monitoring alerts are missing.