Port band allocation

Eleven ports per project, chosen by formula, persisted, and checked before a stack starts.

What it is

A port band is the contiguous range of host ports reserved for one project. The allocator uses a fixed base of 60000 and a block size of 11, with a fixed offset for each of the eleven Supabase services. A project at slot n owns every port from 60000 + 11n to 60000 + 11n + 10.

The allocation is deterministic and persisted. It is not a search for free ports at start time. A reserved block belongs to the project until the project is deleted; released slots become reusable, and the allocator prefers the first never-used slot so the audit trail stays readable.

Why it exists

Supabase services use several ports per stack. Running two stacks with the CLI's defaults produces a collision that is unpleasant to debug: one stack starts, the other half-starts, and the error names a container rather than the port. A reserved block makes collisions impossible between managed projects, and writing the values into config.toml makes the CLI use them.

The 60000 band

Port-band allocation Each project receives a contiguous block of eleven ports starting at 60000. Slot zero begins at 60000, slot one begins at 60011, and slot two begins at 60022. The eleven offsets are fixed service slots. 60000 band · 11 ports per project · base + slot × 11 + offset slot 0 · project A 60000 api60001 db60002 shadow60003 studio… 60010 edge_inspector slot 1 · project B 60011 api60012 db60013 shadow60014 studio… 60021 edge_inspector slot 2 · project C 60022 api60023 db60024 shadow60025 studio… 60032 edge_inspector +11 +11 Offset map inside every block 0 api · 1 db · 2 shadow · 3 studio · 4 inbucket · 5 smtp 6 pop3 · 7 analytics · 8 pooler · 9 edge_runtime · 10 edge_inspector port = 60000 + slot × 11 + offset The legacy 54321 band is preserved for imported stacks; managed blocks never start there. active block next slot

Diagram: the 60000 band divided into blocks of eleven ports, with slot zero at 60000 to 60010 and slot one at 60011 to 60021; each block lists gateway, database, shadow, Studio, mail, SMTP, POP3, analytics, pooler, edge runtime and edge inspector.

Allocated blockLegacy CLI rangeReserved offsets

A worked example

Take a fresh project that receives slot 0. The allocator computes eleven ports:

  • api = 60000 + 0 × 11 + 0 = 60000
  • db = 60000 + 0 × 11 + 1 = 60001
  • shadow = 60002, studio = 60003, inbucket = 60004, smtp = 60005
  • pop3 = 60006, analytics = 60007, pooler = 60008
  • edge_runtime = 60009, edge_inspector = 60010

A second project receives slot 1 and therefore 60011 through 60021. A third receives 60022 through 60032. The arithmetic is executed by the allocator itself; these values are what the formula returns for those slots.

The important property is that the arithmetic is repeatable. Given the same slot, the allocator returns the same eleven ports on every start, and the project's configuration is rewritten to match. That is what lets a saved client configuration survive a restart, as long as the allocation itself does not change.

Persisted allocations

Data and storage layout The manager keeps projects, users and settings in a manager SQLite database in the platform data directory. Each Supabase project keeps its Postgres and storage data in Docker volumes. Project backups are SQL files under the project backup folder. Vault secrets are encrypted before storage. Three layers of state Manager database SQLite file in the platform data directory projects / users / settings port allocations / audit rows loaded in memory via sql.js Per-project data Docker volumes managed by the Supabase CLI Postgres data / storage objects project containers not copied by the builder Project files inside the registered project directory supabase/config.toml supabase/backups/*.sql written on demand Secrets and logs Project secrets and edge-function secrets are encrypted with scrypt and AES under the vault master key before storage. The master key is configuration, not database content. Its previous value can be retained during rotation. Proxy access logs and denial logs live in the manager log directory and follow the admin retention setting. The manager database is rewritten as a whole on mutation; copy it only while the manager is stopped. No product data is copied into docs/ by the site builder. manager project

Diagram: the port_allocations table stores one row per slot with eleven port columns, a unique slot, a unique Supabase project id and a released timestamp; released rows keep their history while their ports become reusable.

Active allocationManager database

Allocation, reuse and legacy projects

The allocator reads every allocation and treats a slot as occupied if any row has ever used it, because the slot column is unique. Ports are considered occupied only for active rows: a soft-released row keeps its history but its ports can be reused. When a released row's slot is chosen again, the row is reclaimed in place, which keeps the unique slot constraint satisfied and preserves the rest of the history.

Imported projects that already ran with the CLI's default ports keep those values as a legacy allocation. The legacy range starts at 54321 and is recorded per project, because a project's existing configuration may already use a non-default block. A managed start later moves the project into the 60000 band.

Failure and recovery

Preflight checks the project's ports before a start. If a port is held by another project, the start is refused with the owner named. If it is held by an unrelated host process, the start is refused too; the manager adopts its own leftover containers but not someone else's process. A crashed session can leave containers behind, and the orphan reconciliation releases allocations whose project is gone or whose containers no longer exist.

The example environment file documents PORT_BAND_BASE and PORT_BLOCK_SIZE, and the setup script validates their presence, but the running allocator does not read them. Changing those values does not change allocation. The constants are the source of truth.

Configuration

<code>PORT_BAND_BASE</code>
Present in the example environment file and validated by setup. Not read by the allocator.
<code>PORT_BLOCK_SIZE</code>
Present in the example environment file as 10. The allocator uses 11, because there are eleven services.
Project port block
Written into the project's supabase/config.toml before a managed start.
Do not size a block from the example environment file. The allocator reserves 11 ports, not 10, and the eleventh is the edge inspector.