Core Concepts
A short glossary-with-context. Everything else in these docs assumes you know these terms.
Deployment, instance, control plane
A deployment (or instance) is one running AnvilBase stack — the Docker Compose project or Kubernetes release. The control plane is the Rust service at its center; it’s what every client talks to. One deployment hosts many projects.
Project
A project is an isolated tenant. Creating one provisions:
- a dedicated Postgres database
platform_<project_id>, - a dedicated storage bucket
bucket-<project_id>with its own encryption key, - a unique JWT secret,
- an
anonkey and aservice_rolekey.
Every project has a UUID (id) and a human slug (e.g. my-app). Most
endpoints are addressed by the UUID. Deleting a project soft-deletes it and
deprovisions the database and bucket in the background.
# Create a project (management plane)curl -X POST http://localhost:39001/api/v1/projects \ -H "Authorization: Bearer $ANVILBASE_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"My App"}'The create response is the only time you see the jwt_secret and
service_role_key — store them immediately. See
Your First Project.
The two API planes
This is the single most important distinction in AnvilBase.
Management plane — /api/v1/*
The control surface: provisioning projects, configuring auth, managing users, wiring webhooks/email, running DDL/migrations, rotating secrets, reading stats and audit logs. Used by operators, the console, and the CLI.
- Credential: an admin token (the value of the
ANVILBASE_ADMIN_TOKENenv var) or a Personal Access Token (anvilbase_pat_…). - Sent as
Authorization: Bearer <token>. - Fails closed — no valid credential means
401. There is no anonymous management surface.
Full catalog: Reference → Management API.
Data plane — /v1/*
The application surface: REST-over-SQL reads/writes, storage, auth flows, edge-function invocation, realtime, and eIDAS wallet flows. Used by your apps and your end users.
- Credential: a per-project API key (
anon/service_role) or a project JWT issued by Better Auth. - Sent as
apikey: <key>and/orAuthorization: Bearer <jwt>.
Full catalog: Reference → Data-Plane API.
Keys are not interchangeable across planes. A
service_rolekey is a data-plane key and is not valid on/api/v1. A PAT is a management-plane credential and is not a data-plane key. Mixing them up is the most common first mistake.
API keys and scopes
Each project is born with two data-plane keys. They map to Postgres roles and determine how RLS treats the request.
| Key | Scope | Bypasses RLS? | Belongs in |
|---|---|---|---|
anon | anon | No | Client code (browser, mobile, public) |
service_role | service_role | Yes | Server-side code only |
A logged-in end user presents a JWT instead, which carries the
authenticated scope and their user id. The key format is
anvilbase_<scope>_<slug>_<random>.
- The anon key is safe to ship in client bundles — by itself it can only read what RLS policies allow, and fresh tables have RLS on with no policies (so nothing is readable until you write a policy).
- The service_role key bypasses RLS entirely — treat it like a database superuser password. Never put it in a browser or mobile app.
See Security → API Keys & Scopes.
JWTs and RLS context
When an end user signs in, Better Auth issues a JWT signed with the project’s JWT secret. On each data-plane request, the control plane validates the JWT and injects context into the Postgres session before running your query:
SET LOCAL ROLE authenticated;SET LOCAL app.current_user_id = '<user-uuid>';SET LOCAL request.jwt.claims = '{...}';Your RLS policies read that context (e.g.
author_id = current_setting('app.current_user_id')::uuid) to decide which rows
the request can see. This is the core of the security model — see
Row Level Security.
Roles (two kinds)
Per-project end-user roles (used in RLS and keys):
anon, authenticated, service_role.
Platform operator roles (who can administer the deployment):
super_admin, project_admin, developer, viewer.
Project membership roles (team management): owner, admin, editor,
read_only. See RBAC & Team Management.
Isolation
“Isolation” in AnvilBase means complete, cross-layer separation between projects — separate database, bucket, secret, cache namespace, and queue namespace. It is enforced at the routing layer before any service is reached, and again by RLS inside Postgres. See Multi-Tenancy.
Secrets vs. the secrets vault
Two different things:
- Deployment secrets live in
.env(database passwords, the control-plane signing secret, etc.) and configure the stack. See Configuration. - The secrets vault is a per-project, encrypted key-value store for your application’s secrets (API keys, connection strings), accessible to your edge functions and code. See Secrets Vault.
Environments (dev / staging / prod)
The CLI models multiple deployments as environments declared in
anvilbase.toml (topology only — no secret values). anvilbase deploy staging
promotes schema + secrets + functions to a named environment, with CI as the
approval gate. See CLI Reference.