Architecture
One process manages many local Supabase stacks. Two entry points route traffic to them, and a reserved port block keeps every stack apart.
System overview
Supabase Local Manager is a single Node and Express process. It serves the React dashboard, the management API and a WebSocket, and it orchestrates any number of local Supabase stacks. Each stack is a normal Docker Compose stack started by the open-source Supabase CLI. The manager does not reimplement Postgres or the Supabase services; it decides where each stack runs, writes its ports into the project's configuration, and gives you one place to operate it.
The process keeps its own state in a SQLite database loaded into memory with sql.js. That state covers projects, manager users, settings, port allocations, backups metadata and vault entries. Project data itself never enters the manager database; it stays in the project's Docker volumes.
Three ideas explain most of the design. First, ports are allocated deterministically from a reserved band, so projects cannot collide. Second, every project is reachable through a shared entry point, so clients never depend on a volatile service port. Third, access is evaluated once, in front of both entry points, so the routing mechanism cannot weaken the policy.
Subsystem map
Diagram: the browser reaches the manager API and the React dashboard; the manager owns the proxy layer, the project lifecycle and port allocator, the manager database and the secret vault; each project is a Supabase CLI stack in Docker.
The two entry points
The path-routed front door listens on FRONT_DOOR_PORT, 6000 by default. The first URL segment is the project's database link: a 16-character identifier drawn from a 38-symbol lowercase alphabet, about 84 bits of entropy, generated with cryptographic randomness. The subdomain proxy listens on PROXY_PORT, 9000 by default, and resolves the project from the Host header as <slug>.<base-domain>.
Both entry points resolve a project and then call the same access evaluator. A manager session grants access only to projects the session owns or to an administrator. A project's own anon or service-role key grants access to Kong service paths without a manager session, matching Supabase's gateway. The postgres-meta route requires the service-role key. An unknown link returns a 404 before credentials are considered, and a non-owner receives a 404 of the same shape, so existence is not disclosed.
Request flow
Diagram: a browser request enters the front door, is resolved to a project by path, is checked by the shared access evaluator, is forwarded to the project's Kong gateway or Studio, and the response returns with its cookie path and location header rewritten.
Port bands
Every managed project owns 11 contiguous ports. The formula is 60000 + slot × 11 + offset, with a fixed offset for each service: gateway, Postgres, shadow database, Studio, mail catcher, SMTP, POP3, analytics, project pooler, edge runtime and edge inspector. The allocator finds the first slot whose ports do not intersect an active allocation. Released slots are reusable, and a slot already used by a released audit row is reclaimed in place rather than duplicated.
The values are constants in portAllocator.ts: base 60000 and block size 11. The example environment file lists PORT_BAND_BASE and PORT_BLOCK_SIZE, and the setup script checks that they exist, but the running allocator does not read them. The code wins, and it reserves 11 ports, not 10.
How the band is laid out
Diagram: the 60000 band split into eleven-port blocks, with the service offset inside each block and the legacy 54321 range shown separately.
Process and storage
The backend workspace is packages/supabase-wrapper. It owns the HTTP routes, the proxy services, project lifecycle, port allocation, Postgres introspection and the manager database. The frontend is a React and Vite single-page application in apps/web; in production the backend serves the built bundle on the manager port.
The manager database sits in the platform data directory. Because the entire database is held in memory and rewritten on mutation, a safe file copy needs the manager stopped or taken between writes. Project Postgres data lives in each project's Docker volumes. Project backups are .sql files under the project's supabase/backups directory, with metadata tracked in the manager database.
Security principles
Manager sessions are JWTs signed with JWT_SECRET, carried in an httpOnly cookie, with a token version for revocation. Cookie-authenticated state changes require a double-submit CSRF token. Project ownership is enforced before a request reaches a project, and the denial path does not disclose existence. Project and edge-function secrets are encrypted at rest with scrypt and AES under VAULT_MASTER_KEY.
The HTTP layer applies strict security headers, central error redaction, rate limiting and a proxy that strips its own management token before forwarding. CLI processes are spawned without a shell. The goal is a small, legible security surface: one policy in front of both entry points, one encryption boundary for secrets, and no ambient authority for a project over the manager.
Subsystem deep dives
Front door
The shared entry point, its resolver and its access evaluator.
Two diagrams
Open front doorPort bands
Deterministic allocation with a worked numeric example.
Two diagrams
Open port bandsStack lifecycle
The state machine for create, start, stop and remove.
Two diagrams
Open stack lifecycleWrapper package
What the backend workspace owns and exposes.
Two diagrams
Open wrapper packageWeb app
The React application's structure and data flow.
Two diagrams
Open web appRequest flow
One API call from browser to project service.
Two diagrams
Open request flowData and storage
Manager database, project volumes, backups and vault.
Two diagrams
Open data and storageSecurity model
Sessions, ownership, encryption, CSRF and headers.
Two diagrams
Open security modelQuality and testing
Test suites, guards and the commands that run them.
Two diagrams
Open quality and testing