The wrapper backend package
The backend workspace that turns one Express process into a control plane for many local Supabase stacks.
What it is
packages/supabase-wrapper is the backend workspace, published internally as @supabase-manager/backend. It is a TypeScript Express service. It owns the management API, the WebSocket, the proxy and front-door services, project lifecycle, port allocation, Postgres introspection, the manager database and the vault. The frontend calls it; it calls the Supabase CLI and each project's services.
The package is the product's control plane in code. Understanding its responsibilities explains why the manager can be a single process without hiding a second service.
Why it is a separate workspace
The repository is an npm-workspaces monorepo with two workspaces: the web application and this backend. The split keeps the browser bundle free of server dependencies and lets the backend be built, tested and packaged on its own. The release build compiles the backend to dist and copies its database migrations alongside it, so a packaged install has everything it needs.
Inside the wrapper package
Diagram: the wrapper package contains the routes, proxy services, lifecycle manager, port allocator, manager database, vault and introspection adapters; arrows point to the Supabase CLI, Docker and the project services.
What it owns
The HTTP surface is split into route modules for projects, admin, auth, settings, pools, notifications and dashboard health, plus system routes. The proxy services resolve a project by path or host, evaluate access, forward the request and rewrite the response. The lifecycle manager spawns the CLI and tracks status. The allocator reserves port blocks. The database layer loads SQLite with sql.js and applies numbered migrations in a transaction with a backup on failure. The vault encrypts secrets under the master key. Introspection adapters talk to postgres-meta and the project's own services.
A management API call
Diagram: a management API call enters the Express routes, passes authentication and CSRF checks, reaches a service module, and reads or writes the manager database or a project service before returning.
Public surface and boundaries
The backend exposes a cookie-authenticated API and a WebSocket. It does not expose a general-purpose database proxy: every project operation goes through a route that checks ownership first. The front door and the subdomain proxy are the only paths that forward arbitrary project traffic, and they share one access evaluator.
Shell execution is restricted to the Supabase CLI and a small number of operations, without a shell. Error responses pass through a central redaction path so internal details are not reflected to clients. The manager's own token is stripped before a proxied request leaves the process.
Failure and recovery
The package refuses to boot without a valid JWT_SECRET and VAULT_MASTER_KEY. Database migrations run in a single transaction with a pre-migration backup; a failed migration is restored rather than left half-applied. The launcher frees orphaned processes on the manager and proxy ports before a start. A failed project operation returns an error for that operation, not a process exit; the manager stays up so the other projects remain manageable.
Configuration
How modules communicate
Routes validate input, authenticate the request and delegate to a service module. Service modules own the behaviour and the database writes; they do not know about the HTTP response shape. The proxy layer sits between the routes and the project, and the lifecycle manager is the only module that spawns the CLI. Keeping those seams narrow is what makes the backend testable without a browser.
The manager database and the vault are shared infrastructure rather than per-route state. A route that needs a secret asks the vault; it does not read the environment directly. A route that needs a project asks the project store; it does not hold its own copy.