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:
RoleRef kindBehaves likeGuide
Environmentmutable brancha git branch โ€” advances as you write, promotablethis page
Releaseimmutable taga git tag โ€” frozen at publish, never movesReleases
Mountread-through layeranother database's release, layered in read-onlyMountable 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 staging env, warm it, then atomically swap into master with one promote. No downtime.
  • Multiple scales for comparison โ€” branch scale-1k / scale-10k / scale-100k after each ingest stage; all stay queryable for benchmarking.

URL pattern

Every endpoint accepts an env scope via the URL prefix:

URLResolves 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:

OperationCallKey
ListGET /api/v2/_envsread
BranchPOST /api/v2/_envs { "name": "v2", "basedOn": "env.master" }read-write
Promote into masterPOST /api/v2/_envs/{name}/promoteread-write
DeleteDELETE /api/v2/_envs/{name}read-write

Promote semantics

promote is an atomic swap, not a move:

  • After promote, env.master and 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.master can'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