Skip to content

Multi-tenancy

Each workspace is a tenant with its own PostgreSQL schema. Isolation is structural: separate schemas, not a tenant_id column that every query must remember to filter on.

A shared control schema holds cross-tenant records — which tenants exist, which users belong to them.

Almost nothing, which is the point. Guest code addresses tables unqualified:

const { rows } = await sql.query<Issue>(`SELECT * FROM ${i}`);

The tenant’s search_path is injected per request, so that query reaches the right schema without you naming it.

Credentials are stored per alias, each with a default workspace, overridable per command:

Terminal window
polymesa retrieve ./config --alias prod --workspace acme
polymesa auth whoami --alias prod --workspace acme

Configuration is per-workspace, so the same directory can be deployed to several — that is how staging and production stay in step.

Every tenant is seeded with a non-login SYSTEM account. Automated writes — scheduled jobs, inbound email — are attributed to it, which is what lets those writes satisfy the foreign keys pointing at __user.

You will see it as the creator of records nothing human touched.

Limits are keyed per tenant and user, so one workspace’s traffic cannot consume another’s budget, and one heavy user cannot starve their colleagues. Anonymous traffic is keyed by client IP instead.