Backups
About 622 wordsAbout 2 min
Backups
The only stateful directory in a Spora install is storage/. The full application state is in the database and the secret key. The rest of the filesystem can be rebuilt from a fresh clone + composer install + php bin/spora spora:install.
What to back up
| Path | What it is | Why |
|---|---|---|
storage/database.sqlite | SQLite database (the entire app state) | The single source of truth for agents, conversations, credentials, plugin data, settings |
storage/secret.key | The libsodium master key (auto-generated by spora:install) | Without it, you cannot decrypt any stored credentials — LLM API keys, plugin settings, etc. |
storage/.plugins_stamp | Plugin loader cache | Lets the plugin loader skip re-discovering installed plugins; safe to lose |
config.php and .env | Operator configuration | DB credentials, Mercure URL, secret key path, mail transport, etc. |
recipes/ | Any custom recipes you’ve added | Operator-added YAML files (the framework’s built-in recipes are in spora-core/recipes/) |
plugins/ | Locally installed plugins | Tracked by Composer, but the composer.lock is the source of truth — plugins/ is reproducible from composer install |
For MySQL, the database is not in storage/. Back it up via mysqldump (or your managed-database snapshot). The connection string lives in .env (SPORA_DB_*).
For Docker: storage/ is bind-mounted in docker/docker-compose.yml — back up the host-side path.
Backup strategy
A reasonable default for a small Spora install:
- Nightly full snapshot of
storage/database.sqlite(ormysqldump),storage/secret.key,config.php, and.env. Compress and store off-host. - Off-host rotation: keep 7 daily, 4 weekly, 6 monthly. Test a restore quarterly.
- Secret key in a separate store — if your backup tool encrypts at rest, the secret key is in the same bucket. For higher assurance, put a copy of
storage/secret.keyin your password manager (it’s a 32-byte binary file — base64 it for storage). composer.lockin version control — the plugin install list is reproducible from a fresh checkout +composer install. Keep the lockfile in the operator repo, not just the framework repo.
What NOT to back up
| Path | Why not |
|---|---|
public/dist/ | Rebuilt from composer install (it’s the spora-frontend Composer package) |
vendor/ | Rebuilt from composer install |
node_modules/ | Rebuilt from npm install (only relevant in dev mode) |
storage/spora.log, storage/php.log | Logs are not state; rotate + archive them, but they’re not the backup target |
.vuepress/.cache/, .vuepress/.temp/ | Build artefacts (docs site only) |
Restore
# 1. Fresh checkout
composer create-project spora-ai/spora my-app
cd my-app
# 2. Restore config + .env + secret key
cp /backup/config.php /backup/.env .
cp /backup/secret.key storage/secret.key
chmod 600 storage/secret.key
# 3. Restore database
# SQLite:
cp /backup/database.sqlite storage/database.sqlite
# OR MySQL: restore the dump
mysql -u root -p spora < /backup/spora.sql
# 4. Reinstall plugins
composer install
# 5. Run migrations (idempotent)
php bin/spora spora:install
# 6. Verify
php bin/spora db:seed --checkIf you lose storage/secret.key, you will need to re-enter every tool credential in the admin UI. The encrypted columns in the database will return errors until you do.
Cron example for SQLite
# /etc/cron.d/spora-backup
# Nightly snapshot, keep 14 days
15 2 * * * spora bash -c '
set -e
cd /var/www/spora
ts=$(date +%Y%m%d-%H%M%S)
tar -czf /backups/spora/spora-$ts.tar.gz \
storage/database.sqlite \
storage/secret.key \
storage/.plugins_stamp \
config.php \
.env
find /backups/spora -name "spora-*.tar.gz" -mtime +14 -delete
'What’s in storage/ exactly
From the framework reference:
storage/
├── database.sqlite # Application database (SQLite default)
├── secret.key # libsodium master key (auto-generated, 32 bytes binary)
├── spora.log # Application logs (PSR-3, Monolog)
├── php.log # PHP error/fatal logs
├── .plugins_stamp # Plugin loader cache
└── .spora_plugin_catalog.json # On-disk Packagist cacheThe first three are state. The logs are not. The caches can be regenerated.
For the framework’s full env-var knobs that affect storage paths, see Environment variables → Logging.