Persistent storage
Everything an app writes inside its container is reset on every deploy. For files that must stay, give the app a volume:
vibe deploy --volumeor in vibe.json:
{ "name": "notes", "volume": true }The app finds the volume at /data; the path is also in DATA_DIR. Use it for SQLite files, uploads and anything else worth keeping:
import path from 'node:path';const dbFile = path.join(process.env.DATA_DIR || './data', 'app.db');How it behaves
Section titled “How it behaves”- One volume per app, 2 GB. Writing beyond that fails with
ENOSPC(no space left on device). The size cannot be changed. - Survives deploys, restarts and server reboots.
- Writable for any user, so images that don’t run as root work too.
- During a deploy the old and the new version briefly run at the same time and share the volume. SQLite handles that with its file locks.
- Never removed by accident. Removing
volumefromvibe.jsonkeeps the existing volume mounted. vibe status <name>shows its size, mount path and state.
Another mount path
Section titled “Another mount path”{ "name": "notes", "volume": { "mountPath": "/app/uploads" } }The path must be absolute and cannot be /, /app, /tmp, /home, /var, /opt, /srv or a system directory. Subdirectories like /app/uploads are fine.
Deleting the data
Section titled “Deleting the data”vibe volume rm notes --yesVolume or database?
Section titled “Volume or database?”A volume with SQLite is the simplest choice for a single app. Use a managed PostgreSQL when several apps share data, when you need concurrent writes from many requests, or when your framework expects Postgres. Use Redis for caches, rate limits, queues and pub/sub.