Environments & Authentication (v2, Beta)
An environment (env) is a named, copy-on-write view into your database. Every
database starts with env.master; you branch new envs from it, write to them
independently, and atomically promote them back โ all without copying data.
Branching a 50 GB database happens in milliseconds and uses essentially no extra
disk; only the changes you make in the new env take space.
Branches, tags & the ref graph
Environments, releases, and mounts are three roles of one underlying mechanism โ a ref: a name that points at a committed database head. Heads are content-addressed and immutable; a ref is just a movable (or frozen) label over one. That single idea is why branching is instant and free:
- Nothing is copied when you branch โ the new ref points at the same head, and only the changes you write afterward take disk. This is copy-on-write layering over an immutable head.
- The three roles differ only in how the label behaves:
| Role | Ref kind | Behaves like | Guide |
|---|---|---|---|
| Environment | mutable branch | a git branch โ advances as you write, promotable | this page |
| Release | immutable tag | a git tag โ frozen at publish, never moves | Releases |
| Mount | read-through layer | another database's release, layered in read-only | Mountable Repositories |
GET /api/v2/_refs lists every ref (branches and releases together) so a console
can render the whole version graph in one call. The rest of this page is the
branch role; Releases covers the tag role and the
branch-vs-tag comparison in depth.
Authentication โ one key, path-selected envs
Two facts prevent almost every auth problem on v2:
1. There is no env-scoped API key. Keys are database-level: a read key
reads any env in the database, a read-write key writes any env. The same key that
reads or writes master reads or writes every env. If you need hard isolation
between tenants, use separate databases (/db/{db}/โฆ), not separate envs.
2. An env is selected purely by URL path โ never by a dot suffix, a request-body field, a query parameter, or a header:
โ
/db/{db}/env/{name}/api/v2/_query (multi-tenant server)
โ
/env/{name}/api/v2/_query (single-db server)
โ /db/{db}/env.{name}/api/v2/_query (dot โ not an env selector)
โ body: { "env": "{name}", ... } (ignored)
So a 401/403 that reads fine on master is almost always an addressing
bug (a dot instead of /env/, or a gateway rewriting the path), and a 401 "not authorized to perform this operation" on a write is almost always a read-only
key on a write endpoint. Confirm the env with GET /db/{db}/api/v2/_envs, then
use the slash form above. (More in Common Errors.)
When to use envs
- Throwaway sandboxes โ branch master, run integration tests, drop the env; each run gets a clean slate without re-uploading.
- Per-user demo copies โ every trial user gets an isolated env branched from a shared template; they mutate freely, the template stays clean.
- Side-prepared releases โ build the next dataset on a
stagingenv, warm it, then atomically swap into master with one promote. No downtime. - Multiple scales for comparison โ branch
scale-1k/scale-10k/scale-100kafter each ingest stage; all stay queryable for benchmarking.
URL pattern
Every endpoint accepts an env scope via the URL prefix:
| URL | Resolves to |
|---|---|
/api/v2/... | env.master (default) |
/env/{name}/api/v2/... | the env named {name} |
/db/{db}/api/v2/... | master in that database |
/db/{db}/env/{name}/api/v2/... | named env in that database |
Switching env is purely a URL change โ point AITO_URL at
โฆ/env/sandbox/api/v2 and every client script targets sandbox instead of
master. Schema, data, queries, and admin all scope identically.
Managing envs
The _envs admin endpoints (shared across v1 and v2 โ the env mechanism is one
mechanism) list, branch, promote, and delete:
| Operation | Call | Key |
|---|---|---|
| List | GET /api/v2/_envs | read |
| Branch | POST /api/v2/_envs { "name": "v2", "basedOn": "env.master" } | read-write |
| Promote into master | POST /api/v2/_envs/{name}/promote | read-write |
| Delete | DELETE /api/v2/_envs/{name} | read-write |
Promote semantics
promote is an atomic swap, not a move:
- After promote,
env.masterand the source env reference the same state; queries against master see the promoted content. - The source env is not deleted โ you can still query it under
/env/{name}/โฆ. - Later writes to the source do not propagate to master; they diverge. Promote again to pick them up.
- Clean up with
DELETE /api/v2/_envs/{name}after a successful promote.
This makes "warm and commit" safe: prepare the next state on the side, verify it with full queries, then promote when ready.
Naming rules
- Allowed:
A-Z,a-z,0-9,.,_,-; must start with a letter or digit. - Max length 128. Names starting with
_are reserved. env.mastercan't appear in/env/{name}/โฆURLs โ master is the unscoped path.
A worked example
The public sandbox is built exactly this way: branch a v2 env
from master, declare the collections, batch-load. The
aito-demo upload-data-v2.js script
is the complete recipe:
AITO_URL=https://your-instance.aito.ai/db/your-db \
AITO_API_KEY=<read-write-key> \
node upload-data-v2.js
Related: Quickstart ยท CollectionDb ยท Common Errors ยท Sandbox