---
title: "Where workspaces are stored"
description: "A workspace is a folder on disk, but you never choose where — the path is derived server-side from the data root, the authenticated tenant, and the slug. Plus the three directories a deployment keeps and the two records behind every workspace."
---

> Documentation Index
> Fetch the complete documentation index at: https://tee.hypetrade.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Where workspaces are stored

Each workspace is backed by its own directory on the service's filesystem — that
is how the underlying engine persists a password-locked container. What the API
deliberately does **not** expose is *where* that directory goes: there is no
filesystem field in `tenants.json` and no path parameter on
`POST /v1/workspaces`. The location is derived, not chosen.

## One data root, set by the operator

Every workspace directory lives under a single root the operator sets once, in
the environment — `WATIVE_DATA_ROOT`. Nothing else in the service builds a path
from configuration. In the shipped image it defaults to
`/var/lib/tee-docker/data`, which the Compose file bind-mounts from a fixed host
path (`/opt/tee-docker/data`).

## One folder per workspace, derived

Within that root, a workspace's folder is computed from two trusted values — the
**authenticated tenant** (from `X-Api-Key`, never a body field) and the
**validated slug**:

```
$WATIVE_DATA_ROOT/
└── <tenantId>/
└── <workspaceSlug>/
    ├── config          workspace metadata
    ├── network         the network registry
    ├── asset           asset catalogue
    ├── log             append-only operation log
    └── accounts/       one entry per account (the encrypted key material)
```

No path component ever comes from raw client input: the slug grammar excludes
`.` and `/`, so traversal is impossible by construction, and a containment check
rejects any resolved path that escapes the tenant's own subtree. That is why
`POST /v1/workspaces` takes only `{ slug, password }` — placement is a uniform
operator concern, identical for every tenant, not a per-request or per-tenant
decision.

Creating the workspace is the **only** operation allowed to initialize storage;
every later unlock opens an existing container and refuses to create an empty one
in its place.

## Two records behind every workspace

A workspace exists as **two** things that must stay in step:

| Record | Where | What it is |
|---|---|---|
| The container | `$WATIVE_DATA_ROOT/<tenant>/<slug>/` | The engine's encrypted workspace — accounts, wallets, key material |
| The ledger row | `state.json`, under `TEE_STATE_DIR` | The service's index of which workspaces a tenant has, and its wallet counts |

Create writes both; delete removes both. This split is why backups must capture
`state/` and `data/` **together, with the service stopped** — a backup that
catches them at different moments, or restores one without the other, can strand
a workspace whose ledger row and on-disk container disagree. See the
[deploy backup notes](/deploy/#redeploys-and-backups).

## The three directories a deployment keeps

Storage is one of three separate directories, each with its own environment
variable, so their concerns never mix:

| Directory | Env var | Container default | Holds |
|---|---|---|---|
| Config | `TEE_CONFIG_DIR` | `/app/config` | `tenants.json` (bind-mounted read-only) and `errors.json` (baked into the image) |
| State | `TEE_STATE_DIR` | `/var/lib/tee-docker/state` | `state.json` — the workspace/quota ledger |
| Data | `WATIVE_DATA_ROOT` | `/var/lib/tee-docker/data` | the per-workspace container folders above |

`TEE_SECRET_HMAC_KEY` — which authenticates tenants and signs session tokens —
lives only in the environment, never on disk. It does not encrypt the containers
themselves: each workspace's `data/` is locked under its own password, which the
service never stores. A restored `data/` still cannot be reached without the key,
because no tenant can authenticate to unlock it.

## Related

- [Deploy](/deploy/) — the persistent directories, mounts, and backups in full
- [Workspaces and tokens](/concepts/workspaces-and-tokens/) — what a workspace is and how a token opens one
- [Networks](/concepts/networks-and-rpc/) — the network registry stored under `network`

Source: https://tee.hypetrade.xyz/concepts/storage/index.mdx
