Gonvex

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.

On this page