Supabase compute and disk sizing
A Supabase project stops being affordable or available for one of four reasons: compute throttle, disk throttle, quota, or read-only. This reference covers every compute size and both disk types, then marks per claim whether the behavior comes from the docs or from a live test here - because some of the interesting parts disagree.
The measured numbers come from a battery written against throwaway
projects on the Management API (free, pro, and team orgs; AWS
ap-southeast-1; 2026-08), each project deleted in the same run. Claims
that were not run are still cited to the docs and labeled as such.
- Compute never upgrades itself; disk never shrinks. Compute resize is a 1-2 minute window (measured); disk decrease is rejected outright.
- Disk autoscale grows at 90% usage by a configurable percent (default 50%). That config cannot be read or written through the Management API at all (measured) - the dashboard is the only surface.
- The free-plan read-only wall is not the documented 500 MB: measured
reads accepted to ~726 MB db size, then
ERROR: 25006: cannot execute INSERT in a read-only transaction. Recover with DELETE (TRUNCATE is also blocked), not vacuum alone. - The disk modification quota answered 429 with text “once per four hours” (measured) - the docs describe four modifications per rolling 24 hours. Enforcement was nondeterministic across runs.
- The “Large compute or above” gate on disk IOPS/throughput is UI-only: the API accepted AND applied elevated IOPS on a Micro project (measured, confirmed by follow-up read).
Pick the pressure first
Section titled “Pick the pressure first”Every section below answers one of those branches, with the measured number in the section body.
Compute sizes
Section titled “Compute sizes”Prices and recommended db size from the docs.1
| Size | Hourly | Monthly | CPU | Memory | Max db (recommended) |
|---|---|---|---|---|---|
| Nano | $0 | $0 | shared | up to 0.5 GB | 500 MB |
| Micro | $0.01344 | ~$10 | 2-core shared | 1 GB | 10 GB |
| Small | $0.0206 | ~$15 | 2-core shared | 2 GB | 50 GB |
| Medium | $0.0822 | ~$60 | 2-core shared | 4 GB | 100 GB |
| Large | $0.1517 | ~$110 | 2-core dedicated | 8 GB | 200 GB |
| XL | $0.2877 | ~$210 | 4-core dedicated | 16 GB | 500 GB |
| 2XL | $0.562 | ~$410 | 8-core dedicated | 32 GB | 1 TB |
| 4XL | $1.32 | ~$960 | 16-core dedicated | 64 GB | 2 TB |
| 8XL | $2.562 | ~$1,870 | 32-core dedicated | 128 GB | 4 TB |
| 12XL | $3.836 | ~$2,800 | 48-core dedicated | 192 GB | 6 TB |
| 16XL | $5.12 | ~$3,730 | 64-core dedicated | 256 GB | 10 TB |
| >16XL | - | - | custom | custom | custom |
Micro through 2XL is shared and burstable; Large and above are dedicated.1 Burstable means spikes are fine until burst credits drain; then baseline governs.
Nano cannot start on a paid org: the try was rejected with
400 Minimum instance size on paid plans is Micro (measured, create +
PATCH + catalogue). On a free org, Nano pauses and restores fine; wake
measured ~162-204 s.
Per-size IO ceiling (docs, unmeasured here)
Section titled “Per-size IO ceiling (docs, unmeasured here)”Baseline = sustained. Max = burst until credits drain.1
| Size | Baseline MB/s | Max MB/s | Baseline IOPS | Max IOPS |
|---|---|---|---|---|
| Nano | 5 | 261 | 250 | 11,800 |
| Micro | 11 | 261 | 500 | 11,800 |
| Small | 22 | 261 | 1,000 | 11,800 |
| Medium | 43 | 261 | 2,000 | 11,800 |
| Large | 79 | 594 | 3,600 | 20,000 |
| XL | 149 | 594 | 6,000 | 20,000 |
| 2XL | 297 | 594 | 12,000 | 20,000 |
| 4XL | 594 | 594 | 20,000 | 20,000 |
| 8XL | 1,188 | 1,188 | 40,000 | 40,000 |
| 12XL | 1,781 | 1,781 | 50,000 | 50,000 |
| 16XL | 2,375 | 2,375 | 80,000 | 80,000 |
The docs go further up to 24XL/48XL at 3,750 / 5,000 MBs baseline.1
Per-size pg limits (docs; micro and small measured here)
Section titled “Per-size pg limits (docs; micro and small measured here)”| Size | rep slots | wal senders | max connections | pooler clients |
|---|---|---|---|---|
| Nano | 5 | 5 | 60 | 200 |
| Micro | 5 | 5 | 60 | 200 |
| Small | 5 | 5 | 90 | 400 |
| Medium | 5 | 5 | 120 | 600 |
| Large | 8 | 8 | 160 | 800 |
| XL | 24 | 24 | 240 | 1,000 |
| 2XL | 80 | 80 | 380 | 1,500 |
| 4XL | 80 | 80 | 480 | 3,000 |
| 8XL | 80 | 80 | 490 | 6,000 |
| 12XL | 80 | 80 | 500 | 9,000 |
| 16XL | 80 | 80 | 500 | 12,000 |
Measured micro: 60/60/10/10 (settings, wal_senders, rep_slots), small 90/90/10/10 - the wal senders and rep slots above are the docs’ plan-wide ceilings; pg’s own floor per size sits lower.1 Downgrading below your replication-slot usage is rejected because the server will not start.1
Resize: duration + downtime (measured)
Section titled “Resize: duration + downtime (measured)”The order micro -> small -> large -> small -> micro was run with REST (anon table read) and Auth health sampled every 250 ms:
| op | settle | REST max contiguous outage | Auth max outage |
|---|---|---|---|
| upgrade micro->small | 105 s | 1.0 s | 0 s |
| upgrade small->large | 61 s | 17.0 s | 0 s |
| downgrade large->small | 61 s | 0 s | 0 s |
| downgrade small->micro | 73 s | 0 s | 0 s |
Adjacent resize PATCHes are rate-limited independent of rebuild: the
second within a window answered 429 We are still processing addon changes, please try again in N minute(s). A separate experiment (500 ms
sampling from AWS) measured the resize pooler window at ~131-207 s.2
Docs cite “typically less than 2 minutes”.1
Compute billing
Section titled “Compute billing”Compute is billed hourly (paused projects don’t accrue) and is NOT spend- cap eligible - the cap only bounds eligible usage items.3
Types (defaults doc-verified)
Section titled “Types (defaults doc-verified)”| gp3 | io2 | |
|---|---|---|
| Price/GB-month | $0.125 | $0.195 |
| IOPS price | $0.024/IOPS-month | $0.119/IOPS-month |
| Throughput | 125 MBs incl, then $0.95/MBs (max 1,000) | scales with IOPS |
| Max IOPS | 16,000 (from 32 GB size) | 80,000 (from 80 GB size) |
| Max size | 16 TB | 60 TB |
| Effective ceiling | min(compute size, provisioned disk) |
Provision more than baseline per GB: gp3 +500 IOPS/GB and +0.25 MBs/IOPS; io2 +1,000 IOPS/GB.1 The lab measured the “Large compute” gate to be UI-only (below).1
Database size vs disk size
Section titled “Database size vs disk size”Database size = pg_database_size() (tables + indexes + materialized
views). Disk = that + WAL + system files + an empty baseline of ~40-60
MB.4 Free plan quota is on the FIRST; paid-plan read-only
trips on the SECOND at 95%.4
- Delete data: db size does not drop until vacuum runs (dead tuples); TRUNCATE drops instantly. Both measured.
- Disk util endpoint (
GET /config/disk/util) answered 200 on free AND pro (measured) - usable in org-wide cost probes.
Autoscale: defaults and the missing surface
Section titled “Autoscale: defaults and the missing surface”Docs describe: trigger 90% usage, grow by growth percent (default 50%), min increment 1 GB, bounded by max size default 8 GB with the spend cap on.4
Measured: the whole thing is invisible to the Management API. On both Pro and Team orgs the autoscale GET returned an empty shape and PUT/POST /PATCH all answered 404. The dashboard’s editable growth/min/max fields are the only mutation surface - the same pattern the http-tier-lockdown experiment found for the Data API toggle. Tracking these values is a manual IaC exercise.
On the free tier: measured baseline disk was 2 GB (docs claim 1 GB) and the disk did NOT grow at 90%+ through a fill - here autoscale did not save you from the read-only anyway.4
Manual expansion + modification quota
Section titled “Manual expansion + modification quota”Increase is OK (HTTP 201, +200 GB cap per change); decrease is refused (HTTP 400, measured).4
Modification quota measured: 429 Database disk can only be modified once per four hours. Last modified at <UTC> - directly contradicting
the docs’ “four modifications within a rolling 24-hour
window”.4 One run also accepted 5 consecutive increases in
one burst; plan for a cooldown you cannot schedule around, and raise
the disk before bulk imports bigger than ~1.5x the current db size.
Read-only mode
Section titled “Read-only mode”Free plan (measured): accepts to ~726 MB db size, then a write fails
with ERROR: 25006: cannot execute INSERT in a read-only transaction;
a SELECT on the management endpoint answered 201 the whole time. The
documented 500 MB was not the boundary in this run,4 and
recovery required DELETE (TRUNCATE was rejected) or the override GUC
set default_transaction_read_only = 'off' once below the
threshold.4
Paid plans: docs trigger at 95% disk util (not run here).4
Disk IOPS/throughput gate (dashboard-only)
Section titled “Disk IOPS/throughput gate (dashboard-only)”Dashboard: “Adjusting your disk configuration requires LARGE Compute size or above.” Measured: the raise was accepted AND stuck on Micro, verified by follow-up GET. The gate is a UI gate; a PAT bypasses it silently, and IOPS billing starts regardless.
Spend cap (and where compute/disk escape it)
Section titled “Spend cap (and where compute/disk escape it)”Spend cap ON = eligible overages blocked past quota after notification + grace period, ending in Fair Use restriction; it is billing-path enforcement, not a request-path breaker (measured).3
Exclusions (never capped): compute hours, disk throughput, disk IOPS-hours, custom domains, PITR, read replicas, IPv4, branching, advanced MFA/SSO, log drains.3 Team plan has no spend cap at all - overages are simply billed.3
Ops playbook
Section titled “Ops playbook”- Pre-bulk-import: measure; if the import is larger than ~1.5x the current db size, expand the disk manually first (single POST), or the quota kills it mid-import and read-only follows. Then re-check the quota status before a second attempt.
- Resize sequencing: wait >= 2 minutes between adjacent resize
PATCHes, or the second returns 429 with
still processing. - Sizing cues: CPU utilization +
Disk IO % consumed(the burst-budget drain metric: >0 means past baseline). Over it -> upgrade.1 - Autoscale settings: cannot be observed via API; pin their intended state in IaC and audit the dashboard manually.
Where the docs disagree with runtime
Section titled “Where the docs disagree with runtime”| Doc claim | Runtime measured | Severity |
|---|---|---|
| read-only at 500 MB db (free) | read-only at ~726 MB, reads survivor | docs stale |
| 4 modifications / 24 h | 429 once/4h, nondeterministic | docs text differs, quota exists |
| free disk starts 1 GB | started 2 GB | docs understate |
| Large-only for IOPS/throughput | accepted + applied on Micro | UI-only gate |
| autoscale config via API | verbs 404; GET empty | surface gap |
Each measured row above comes from the supabase-lab pvlab harness, module ids D01-D09 under experiments/compute-disk, 2026-08-19, and re-runs are driven from the experiment’s probe scripts - the full run log is RUNLOG.md (the top-level consolidated reference also lives at the repo root: COMPUTE-DISK.md).
Reading the numbers
Section titled “Reading the numbers”- Settle seconds are measured from PATCH -> ACTIVE_HEALTHY status flip. Treat them as a floor; longer providers and disks stretch it.
- contiguous-outage values in the resize table are the MAX visible gap across sampled clients - percent-ok inside a window can dip below that without creating an officially long gap.
- Disk quota behavior varied run to run (bursts accepted, then reject); treat it as volatile, not a number to schedule against.
References
Section titled “References”-
Supabase, “Compute and Disk,” Supabase Docs. https://supabase.com/docs/guides/platform/compute-and-disk ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
supabase-lab, “Platform-downtime experiment,” supabase-lab runlog. https://github.com/erfianugrah/supabase-lab/tree/main/experiments/platform-downtime ↩
-
Supabase, “Cost Control - Spend Cap,” Supabase Docs. https://supabase.com/docs/guides/platform/cost-control ↩ ↩2 ↩3 ↩4
-
Supabase, “Database Size,” Supabase Docs. https://supabase.com/docs/guides/platform/database-size ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9