|
| 1 | +--- |
| 2 | +title: Backup & Restore |
| 3 | +description: What state an ObjectStack deployment actually holds, how to back up each piece per database driver, and the restore drill to rehearse before you need it. |
| 4 | +--- |
| 5 | + |
| 6 | +# Backup & Restore |
| 7 | + |
| 8 | +The [go-live checklist](/docs/deployment/production-readiness#go-live-checklist) |
| 9 | +requires a documented, tested backup/restore drill. This page is that drill: |
| 10 | +what to back up, how, and how to prove the restore works. |
| 11 | + |
| 12 | +## What state a deployment holds |
| 13 | + |
| 14 | +An ObjectStack app is deliberately easy to back up because almost everything |
| 15 | +lives in one of four places: |
| 16 | + |
| 17 | +| State | Where it lives | Backup strategy | |
| 18 | +|:---|:---|:---| |
| 19 | +| **Business data** (records, users, orgs, runtime-authored metadata, encrypted `sys_secret` values) | The database behind `OS_DATABASE_URL` | Database-native backup — see below | |
| 20 | +| **Authored metadata** (objects, views, flows, …) | Your project source + the compiled artifact | Git. The artifact is rebuildable with `os build`; no runtime backup needed | |
| 21 | +| **Secrets** (`OS_SECRET_KEY`, `OS_AUTH_SECRET`, DB credentials) | Your secret manager | Escrow the values themselves — see the warning below | |
| 22 | +| **The ObjectStack home dir** (`~/.objectstack` or `<cwd>/.objectstack`: default SQLite DB under `data/`, uploaded files under `data/uploads/`, dev-minted keys) | Local filesystem | Include in file backups on single-host deployments; empty on stateless containers that set `OS_DATABASE_URL` + `OS_SECRET_KEY` explicitly | |
| 23 | + |
| 24 | +<Callout type="warn"> |
| 25 | +**A database backup without `OS_SECRET_KEY` is an incomplete backup.** Every |
| 26 | +`sys_secret` value (encrypted settings, `secret` fields, datasource |
| 27 | +credentials) is encrypted under that one key. Restoring the database on a new |
| 28 | +host without the original key leaves those values permanently undecryptable. |
| 29 | +Escrow the key in your secret manager the day you generate it, and treat |
| 30 | +key + database as one backup unit. |
| 31 | +</Callout> |
| 32 | + |
| 33 | +## Backing up the database |
| 34 | + |
| 35 | +Use the native tooling of whatever `OS_DATABASE_URL` points at — ObjectStack |
| 36 | +adds no extra backup surface on top of the database. |
| 37 | + |
| 38 | +### PostgreSQL |
| 39 | + |
| 40 | +```bash |
| 41 | +# Logical backup (small/medium databases; restore with pg_restore) |
| 42 | +pg_dump --format=custom "$OS_DATABASE_URL" > backup-$(date +%F).dump |
| 43 | + |
| 44 | +# Larger deployments: continuous archiving / point-in-time recovery |
| 45 | +# (WAL archiving, or your provider's managed snapshots) |
| 46 | +``` |
| 47 | + |
| 48 | +### SQLite (single host) |
| 49 | + |
| 50 | +The database is a single file — but never copy it while the server is |
| 51 | +writing. Use SQLite's online backup instead: |
| 52 | + |
| 53 | +```bash |
| 54 | +sqlite3 /srv/data/app.db ".backup '/backups/app-$(date +%F).db'" |
| 55 | +``` |
| 56 | + |
| 57 | +The default location when `OS_DATABASE_URL` is unset is |
| 58 | +`<home>/data/objectstack.db` under the ObjectStack home directory. |
| 59 | + |
| 60 | +### Turso / libSQL and managed databases |
| 61 | + |
| 62 | +Use the provider's snapshot, branching, or point-in-time-restore facilities. |
| 63 | +Nothing ObjectStack-specific applies. |
| 64 | + |
| 65 | +## Backing up uploaded files |
| 66 | + |
| 67 | +The local storage adapter keeps uploads under `OS_STORAGE_ROOT` (default |
| 68 | +`./.objectstack/data/uploads`). On single-host deployments, include that |
| 69 | +directory in the same schedule as the database so records and their |
| 70 | +attachments restore to the same point in time. Deployments using an external |
| 71 | +storage service (S3-compatible, etc.) inherit that service's durability and |
| 72 | +versioning instead. |
| 73 | + |
| 74 | +## The restore drill |
| 75 | + |
| 76 | +Rehearse this on a scratch host **before** go-live, and again after any |
| 77 | +storage change. A backup you haven't restored is a hope, not a backup. |
| 78 | + |
| 79 | +<Steps> |
| 80 | + |
| 81 | +### Provision a clean host |
| 82 | + |
| 83 | +Fresh container or VM. Install Node 18+ and `@objectstack/cli`. |
| 84 | + |
| 85 | +### Restore the database |
| 86 | + |
| 87 | +```bash |
| 88 | +pg_restore --clean --if-exists -d "$OS_DATABASE_URL" backup-2026-07-14.dump |
| 89 | +# or copy the SQLite file / restore the provider snapshot |
| 90 | +``` |
| 91 | + |
| 92 | +### Provide the original secrets |
| 93 | + |
| 94 | +Set `OS_SECRET_KEY` and `OS_AUTH_SECRET` to the **escrowed originals** — not |
| 95 | +freshly generated values. Restore `OS_STORAGE_ROOT` contents if you use local |
| 96 | +file storage. |
| 97 | + |
| 98 | +### Boot from the artifact and verify |
| 99 | + |
| 100 | +```bash |
| 101 | +OS_ARTIFACT_PATH=./objectstack.json OS_PORT=8080 os start |
| 102 | +curl -fsS http://localhost:8080/api/v1/health |
| 103 | +curl -fsS http://localhost:8080/api/v1/ready |
| 104 | +``` |
| 105 | + |
| 106 | +Then prove the restore end-to-end: sign in with a real account, open a record |
| 107 | +that existed before the backup, and read a value that lives in an encrypted |
| 108 | +setting (which exercises `OS_SECRET_KEY`). |
| 109 | + |
| 110 | +</Steps> |
| 111 | + |
| 112 | +## Retention is not backup |
| 113 | + |
| 114 | +The platform's `lifecycle` declarations bound telemetry data (activity 14d, |
| 115 | +job runs 30d, notifications 90d, audit 90d-hot) — deleted-by-policy data is |
| 116 | +gone from backups taken afterwards. If compliance needs longer, extend |
| 117 | +`lifecycle.retention_overrides` **before** go-live, and register an `archive` |
| 118 | +datasource if audit data must move to cold storage instead of being retained |
| 119 | +hot. See [Production Readiness](/docs/deployment/production-readiness). |
| 120 | + |
| 121 | +## Related |
| 122 | + |
| 123 | +- [Self-Hosted Deployment](/docs/deployment/self-hosting) |
| 124 | +- [Production Readiness](/docs/deployment/production-readiness) |
| 125 | +- [Environment Variables](/docs/deployment/environment-variables) |
| 126 | +- [Drivers](/docs/data-modeling/drivers) |
0 commit comments