Skip to content

Persistent storage

Everything an app writes inside its container is reset on every deploy. For files that must stay, give the app a volume:

Terminal window
vibe deploy --volume

or 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');
  • 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 volume from vibe.json keeps the existing volume mounted.
  • vibe status <name> shows its size, mount path and state.
{ "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.

Terminal window
vibe volume rm notes --yes

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.