> ## Documentation Index
> Fetch the complete documentation index at: https://docs.avocadostudio.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# State and backups

> Where the orchestrator keeps draft pages, history and sessions, what is not persisted, how snapshots work, and what a clean shutdown does.

The orchestrator holds real work that is not in your CMS yet — drafts people
have not published, undo history, the version log. This page is what an operator
needs to know about where that lives and how to keep it.

## One SQLite file

Session state — draft pages, history, the version log, chat history, site
configs, issue-touched slugs — lives in a single SQLite file managed by
`better-sqlite3`.

Mutations are coalesced: a request's synchronous writes are debounced for 30 ms
and then snapshotted into SQLite inside one transaction, rather than each write
hitting the disk on its own.

### Files on disk

Under `.data/` by default:

| File                                         | What it is                                                                  |
| -------------------------------------------- | --------------------------------------------------------------------------- |
| `orchestrator.db`                            | the live state                                                              |
| `orchestrator.db-wal`, `orchestrator.db-shm` | SQLite's write-ahead log and shared-memory index                            |
| `orchestrator-state.json.migrated-<iso-ts>`  | a one-shot archive of the legacy JSON writer's output, kept as a safety net |
| `.db.backup-<ts>`                            | rolling snapshots                                                           |

<Warning>
  **`.data/` must be in `.gitignore`.** The orchestrator writes it into the project
  root on the first request, and `create-next-app`'s `.gitignore` does not cover
  it — so the first `git add .` after the first run commits a database.
</Warning>

### Configuration

| Variable                                | Default                 | What it does                                                                                                                                      |
| --------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ORCHESTRATOR_DB_FILE`                  | `.data/orchestrator.db` | Path to the database. Auto-switches to `:memory:` under `NODE_ENV=test`; set it to the literal `:memory:` to force ephemeral state in production. |
| `ORCHESTRATOR_DB_BACKUP_INTERVAL_HOURS` | `24`                    | How often a `VACUUM INTO` snapshot is taken                                                                                                       |
| `ORCHESTRATOR_DB_BACKUP_LIMIT`          | `14`                    | How many rolling snapshots to keep                                                                                                                |
| `ORCHESTRATOR_STATE_FILE`               | —                       | A legacy JSON state file, read once on first boot. It is renamed after migration and never rewritten.                                             |
| `ORCHESTRATOR_JSON_MIGRATION_TTL_DAYS`  | `14`                    | Retention for that archive before it is swept                                                                                                     |

## Backups

A periodic `VACUUM INTO` writes a consistent snapshot without stopping the
server — every 24 hours by default, keeping the last 14.

That gives you point-in-time recovery inside the retention window and nothing
outside it. **If the draft state matters to you, copy those snapshots off the
volume**, the same way you would for any other database. Snapshot count and
interval are the two dials.

Restoring is a file copy: stop the orchestrator, put the snapshot in place of
`orchestrator.db` (removing the `-wal` and `-shm` files alongside it), start it
again.

## What is capped

State does not grow without limit. The caps are per site, and hitting one
discards the oldest entry rather than failing:

| What             | Cap                                |
| ---------------- | ---------------------------------- |
| Undo/redo stacks | 50 entries per page, per direction |
| Version log      | 100 entries                        |
| Recent edits     | 10                                 |
| Chat history     | 6 messages                         |

The practical consequence for the people using the editor is on
[review and undo](/editing/review-and-undo): history is deep, but it is not
forever.

## What is *not* persisted

Several things live only in memory and are gone on restart, by design:

* pending approval plans awaiting an Apply/Discard decision
* continuation chains
* publish status
* per-session image-source preferences

So a restart mid-review loses the held plan, not the draft. The person is asked
again; nothing they had already applied is affected.

## Shutdown

`SIGTERM` and `SIGINT` run three steps in order:

1. `app.close()` — drain in-flight handlers
2. `persistStateNow` — flush any debounced write
3. `resetStore()` — checkpoint the WAL

Give the container time to do that. A hard kill during step 1 can lose up to the
last 30 ms debounce window, and skipping step 3 leaves a WAL for the next boot to
recover from — survivable, but not free.

## Running with no durable state

Setting `ORCHESTRATOR_DB_FILE=:memory:` is legitimate for a public demo or an
ephemeral preview environment, where losing drafts on restart is the point.
[Demo mode](/operations/demo-mode) is the other half of that setup.

Anywhere else, a serverless or otherwise ephemeral filesystem is a trap: the
orchestrator will appear to work and silently lose every draft that was not
published before the instance recycled.

## Deploying

* [Docker](/operations/docker-deployment) — mount a persistent volume at the
  directory holding `ORCHESTRATOR_DB_FILE`
* [Vercel](/operations/vercel-deployment) and
  [Netlify](/operations/netlify-deployment) — the site and editor deploy there;
  the orchestrator needs somewhere with a real disk
* [Security and access](/reference/security) — what has to be set before any of
  this is reachable
