Backup and restore
AutoAir's data lives in three places. Back up all three, with the same schedule and retention:
| What | Where | Why it matters |
|---|---|---|
| DAGs | The deploy target: a local folder, object storage, or a git repository | The specs (<dag_id>.autoair.json), generated DAG files and version history. This is what Airflow runs |
| AutoAir state | The state store: files under <state> or a SQLite/PostgreSQL database | Templates, audit trail, reviews and proposals, AI memory, AI audit, AI rules, MCP servers, icons, the UI-chosen deploy target, users seen |
| Keys and configuration | Your secret store and configuration management | Encryption and signing keys, credentials, settings. Without the encryption key, stored secrets cannot be decrypted |
<state> is <dags_folder>/<subfolder>/.autoair/ unless individual stores were moved with *_url settings; see Database.
Deploy target
| Target | What to back up | Notes |
|---|---|---|
local | The whole output folder (<dags_folder>/<subfolder>/), including .autoair/history/ (version snapshots) and .autoair/state/ (hashes of generated files) | .autoair/history/ is what the Versions panel shows. If the state store is also on the file backend, the same folder holds <state> (see below), so one backup covers both |
object | The bucket prefix (storage.object_url) | Enable bucket versioning; it doubles as point-in-time recovery |
git | The repository, including branches autoair/* with open pull requests | The git host is the source of truth and usually already backed up. History is the commit log. Back up the clone cache (storage.git.cache_dir) only if you want faster start-up |
team_storage targets are separate deploy targets: back up each one.
State store
File backend
Back up <state> and every location you moved with a *_url setting:
| Path (default) | Content |
|---|---|
templates/ | Saved templates (templates_url) |
audit/ | Audit trail, JSON lines per day and process (audit_url) |
proposals/ | Deploy proposals and reviews (iam.proposals_url) |
icons/ | Custom icons and assignments.json (icons_url) |
users/ | Users seen (admin panel) |
deploy-target.json | The deploy target chosen in the UI (no secrets) |
ai-audit/, ai-memory/, ai-knowledge/, ai-users/, ai-threads/, ai-rules/, ai-mcp-servers/, ai-troubleshoot/ | AI stores |
collab.key | Co-editing ticket key (only when neither collab_secret nor Airflow's jwt_secret is set) |
ai-user-llm.key | Fernet key for per-user AI keys and MCP server headers (only when ai.user_llm.encryption_key is unset) |
The files are written atomically one by one, so a file-level copy taken while AutoAir runs is consistent per file. For a consistent snapshot across files, use a volume or file-system snapshot, or stop writes briefly. Caches (ai-research-cache/, cache_dir) do not need a backup.
SQLite
Back up the database file (default <state>/autoair.db) with SQLite's online backup, not a plain copy of a file that is being written (the WAL journal holds recent changes):
sqlite3 /opt/airflow/dags/autoair/.autoair/autoair.db ".backup '/backup/autoair-$(date +%F).db'"
PostgreSQL
Back up the AutoAir schema or tables with your usual PostgreSQL tooling (base backups and WAL archiving, or logical dumps):
# AUTOAIR_DATABASE__URL is a SQLAlchemy URL (postgresql+psycopg://...); the PostgreSQL tools
# need the plain postgresql:// form. A password set separately (AUTOAIR_DATABASE__PASSWORD)
# goes into PGPASSWORD.
export PG_URL="${AUTOAIR_DATABASE__URL/postgresql+psycopg:/postgresql:}"
export PGPASSWORD="$AUTOAIR_DATABASE__PASSWORD" # only when the URL has no password
# everything AutoAir owns, when it has its own schema (database.schema_name=autoair)
pg_dump --format=custom --schema=autoair --file=autoair-$(date +%F).dump "$PG_URL"
# when it shares a schema, select its tables by prefix (database.table_prefix=autoair_)
pg_dump --format=custom --table='autoair_*' --file=autoair-$(date +%F).dump "$PG_URL"
Include <prefix>schema_version: it records which migrations were applied. The documents table's secrets collection holds keys generated by AutoAir (co-editing ticket key, the Fernet key when none is configured), so the database backup contains them; protect it like a secret.
Keys and configuration
Back up, in your secret store:
AUTOAIR_AI__USER_LLM__ENCRYPTION_KEY(or the generated key:ai-user-llm.keyon the file backend, the database'ssecretscollection on SQL). Without it, per-user AI keys and MCP server headers stored in the admin panel cannot be decrypted; users must re-enter them and admins must re-enter the headers.AUTOAIR_COLLAB_SECRET(losing it only invalidates open co-editing tickets for up tocollab_ticket_ttl).AUTOAIR_AI__SERVICE__SHARED_SECRET, git tokens or GitHub App keys,AUTOAIR_DATABASE__PASSWORD, TLS certificates and keys, the marketplace signing key (autoair marketplace keygenoutput).- Your configuration files and environment (
autoair config show --changedprints what differs from the defaults, with secrets masked; keep it with each backup for reference).
Airflow-side items AutoAir relies on (connections such as storage.git.conn_id, per-user git_<username> connections, FAB roles created by autoair iam sync-fab) are backed up with Airflow's metadata database.
Restore
- Stop AutoAir (all replicas), or scale it to zero, so nothing writes during the restore.
- Restore the deploy target: the output folder, the bucket prefix, or the git repository. For git, open pull requests on
autoair/*branches come back with the repository. - Restore the state store:
- file backend: copy
<state>(and moved*_urllocations) back, preserving file modes (collab.keyis0600); - SQLite: copy the backup file to
database.url(or<state>/autoair.db); - PostgreSQL:
pg_restore --clean --if-exists --dbname="$PG_URL" autoair-<date>.dump(PG_URLandPGPASSWORDas for the backup) into the same schema and table prefix.
- file backend: copy
- Restore keys and configuration: the same
ai.user_llm.encryption_key,collab_secret, shared secrets and settings as at backup time. - Check the schema (SQL backends):
autoair db current. If you restored a backup taken before an upgrade and now run a newer AutoAir, apply migrations withautoair db upgrade(or letmigrate_on_startdo it). Restoring a database taken from a newer AutoAir into an older one is not supported: restore the matching version. - Start AutoAir and verify.
Verify
| Check | How |
|---|---|
| Server healthy | GET /api/ready answers 200; the storage check is ok |
| Schema current | autoair db current shows no pending migrations; admin panel Database tab shows Up to date and plausible row counts |
| DAGs present | The builder's DAG list shows the expected DAGs; open one and check its Versions history |
| Templates | The templates gallery and the admin panel's Templates tab list saved templates |
| Audit trail | The admin panel's Audit tab shows records up to the backup time |
| Approvals | The Approvals tab shows pending proposals (proposals older than iam.proposal_ttl_seconds are discarded) |
| Deploy target | The admin panel's Overview shows the expected deploy target and its source (settings or ui) |
| Encrypted data | A user with a personal AI model can still use it; MCP servers in the admin panel pass Test connection |
| End to end | Validate and deploy a test DAG to a non-production environment |
Practise the restore regularly on a staging deployment; an untested backup is not a backup.