Roadie is multi-tenant from the ground up. Your account nests in three levels — organization → project → environment — and isolation is enforced not just in application code but by Postgres row-level security, so one tenant can never read or write another’s data.

The three levels

Organization

The billing and isolation boundary. Members, roles, plan, and everything below belong to exactly one organization.

Project

A unit of configuration inside an org: provider credentials, model aliases, auth config, and the default privacy mode.

Environment

development and production inside a project — each with its own keys, credentials, limits, and log-privacy default.
Every level carries the id of the organization above it, all the way down, and composite foreign keys force each child’s org_id to match its parent’s — so a project, environment, key, or log can never belong to one org while pointing at another’s resource.

What lives at each level

Environments: development and production

When you create a project, Roadie automatically creates exactly two environments — development (the default) and production. There is no staging environment and no route to add arbitrary ones; a project always has these two. Each environment is fully isolated: its own keys, its own provider credentials, its own limits, and its own log-privacy default (development captures more; production defaults to metadata-only — see Privacy modes). A secret or publishable key belongs to exactly one environment, so which environment you call is determined by which key you send. You can edit an environment’s privacy_mode and log_retention_days, but not rename, add, or delete environments.

Isolation is enforced in the database

Tenant isolation does not rely on every query remembering to filter by org. Instead:
  • Every tenant table carries a NOT NULL org_id and a row-level-security policy of the form org_id = current_setting('app.org_id')::uuid.
  • All tenant data is read and written through a single funnel that opens a transaction and sets the app.org_id setting for that transaction only. Every statement in that transaction — even a raw query — is filtered to the current org. Code cannot reach the database any other way.
  • Tables are marked FORCE ROW LEVEL SECURITY, so even the role that owns the tables is subject to the policies (production app roles are not superusers, which are the only roles that bypass RLS). A missing or wrong org context returns no rows, and an insert with a mismatched org_id is rejected by the policy’s write check.
The one deliberate exception is the users table — a mirror of your identity provider’s users — which is not tenant-scoped, because a single person can belong to several organizations. A user’s access to an org is expressed through org membership, not through row ownership.
The audit log is append-only: even inside a valid org context, updates and deletes to audit events are denied at the database level. Every control-plane mutation writes its audit record in the same transaction as the change itself.

The control-plane surface

You manage tenancy through the control plane (dashboard session or a management key). The core routes: Creating a project is what provisions its development and production environments. Members and invitations have their own routes under the organization.

Where to go next