# Data & multi-tenancy

> The single-file vault store, collections, and the file-per-tenant model.

_Updated: 2026-06-11_

Railbase has no external database. All of your data lives in a single encrypted
file managed by an in-process engine. This keeps operations trivial: one process,
one file to back up.

## The vault

The store is an encrypted, MVCC **document store** kept in one file —
`pb_data/railbase.vault` by default. "MVCC" means readers never block writers, so
the single-file model still serves concurrent traffic well. The file is encrypted
at rest with a master key (`pb_data/.secret`) and unlocked at boot with your vault
password (see [Installation](installation) and [Security](security)).

What this means for you:

- **No connection string, no DB server, no migrations service.** Schema
  migrations apply automatically on boot.
- **Backups are a file copy.** A snapshot is a byte-exact copy of the `.vault`
  file — see [Backups & restore](backups-and-restore).
- **Keep it on local disk.** Use the VPS's local disk, not a network mount, for
  correct file locking and durability.
- **A single document can be up to 4 MiB.** Documents larger than a storage
  page are split across pages transparently; past 4 MiB a write is rejected
  with an explicit error. Store large payloads as [files](rest-api#files), not
  document fields. (The REST create endpoint additionally caps a request body
  at 1 MiB.)

## Collections

Data is organized into **collections** (think tables). The core owns the
system collections (users, sessions, audit log, settings); each plugin owns its
own, namespaced by slug (e.g. an inventory plugin's collections are prefixed so
they never collide with another plugin's).

When you uninstall a plugin its collections are left dormant rather than deleted,
so reinstalling restores your data. A separate, backup-gated *purge* permanently
removes them — see [Installing plugins](installing-plugins).

## Multi-tenancy

For deployments that serve multiple isolated organizations, Railbase uses
**row-level tenancy inside the one vault file**. Tenants are registered in the
built-in `_tenants` collection — from the CLI:

```bash
./railbase tenant create acme
./railbase tenant list
```

A collection opts into tenancy with the `.Tenant()` mixin in the
[schema](schema). Its rows then carry a `tenant_id` column, and the scope comes
from the request: a call with an `X-Tenant: <tenant-uuid>` header (the
[TypeScript SDK](typescript-sdk)'s `rb.setTenant(id)`) writes and reads only
that tenant's rows — the value is stamped on insert and filtered on read.
Requests without the header operate at **site scope**. Roles can likewise be
granted per tenant ([RBAC](authentication)).

> [!TIP]
> A single-tenant deployment is just the default case: no tenant setup, no
> `X-Tenant` header, no `.Tenant()` mixins required. Reach for multi-tenancy
> only when you actually host separate organizations on one instance. Note that
> backups operate on the whole vault file — i.e. on all tenants at once.
