Projects and Tenants
How Gonvex routes projects, users, and isolated tenant databases.
Projects and Tenants
A Gonvex runtime can host multiple projects. A project uses either one application database or an isolated runtime-created database for each tenant.
Definitions
Project
One application/product. It has schema, functions, deployments, allowed origins, and tenant settings.
Tenant
One customer/account/workspace inside a project. A tenant can have isolated data.
Landlord database
Runtime control database. Stores projects, tenants, users, memberships, roles, routes, and tenant DB connections.
Tenant database
App data database for one tenant or a shard/group of tenants.
Why A Landlord Database Exists
The runtime cannot route requests by reading the app database first, because it needs to know which app database to connect to.
The landlord database answers:
Which project is this request for?
Which tenant is active?
Which database/schema should be used?
Which user is making the request?
Can this user access this tenant?
Which roles/permissions apply?
Runtime Routing
Every request and subscription resolves this context:
runtime host/origin/token
-> project
-> user
-> active tenant
-> tenant database connection
-> role/permission scope
-> execute function
The frontend can send an active tenant ID, but the runtime must verify that the authenticated user belongs to that tenant.
Tenant Database Strategies
The current project modes are:
single
The project uses one application database and one project-wide scope.
multiTenant
Every runtime-created tenant receives an isolated PostgreSQL database.
Choose the mode with gonvex project create --database-mode single|multiTenant. Schema-per-tenant, shared-table, and hybrid sharding modes
are not implemented.
Dashboard Requirements
The dashboard provides:
- project list screen
- create project screen
- project switcher
- tenant list inside a project
- create tenant screen
- tenant switcher inside a project
- user/membership view
- role/permission view
- project environment variables
- tenant database connection status
CLI Requirements
Project lifecycle:
npx gonvex project list
npx gonvex project create my-product
npx gonvex project select <project-id>
Tenant and membership lifecycle is under gonvex auth:
npx gonvex auth tenants list
npx gonvex auth tenants create "Acme" --owner owner@acme.example
npx gonvex auth memberships list --tenant <tenant-id>
npx gonvex auth memberships add --tenant <tenant-id> --email user@example.com
There is no top-level gonvex tenant command yet.
Function Context
Backend functions receive tenant, project, user, permissions, database, storage, scheduler, and project environment context:
func ListTasks(ctx *gonvex.QueryCtx, args ListTasksArgs) ([]Task, error) {
tenantID := ctx.TenantID
if ctx.User == nil {
return nil, errors.New("authentication required")
}
return queryTasks(ctx.Context, ctx.DB, tenantID, args)
}
Application code should not trust tenant IDs from the client without runtime verification.
Generated Bindings In Multi-Tenant Apps
Generated bindings are project-level. Tenant selection is runtime/session state.
The client might look like:
const client = new GonvexClient("wss://runtime.example.com/ws", {
project: "my-product",
});
client.setAuth({ token: sessionToken, tenant: "acme" });
Then all queries/mutations execute against the verified active tenant.
For the current React client wiring and safe tenant-switching pattern, see Frontend Multitenancy.