Persistent Volumes: Don't Lose Data on Redeploy
Anything not declared as a volume lives inside the container and disappears on the next deploy — three ways to declare one.
Why this matters
A redeploy replaces the container. Anything written to the filesystem inside it — an uploaded file, a SQLite database, a generated cache — is gone the moment the old container is removed, unless it lives in a declared volume instead.
Named Docker volumes
volumes:
uploads: /app/storage/uploads
Neo creates a Docker volume named <app>-uploads and mounts it at that path. It persists across redeploys, lives entirely in Docker's own storage, and survives even if you don't know or care where on the host filesystem it physically sits.
Bind mounts to a host path
volumes:
logs: /var/log/myapp:/var/log/app
host:container form — useful when something on the host (a log shipper, a backup script) needs to read the files directly, not just the app.
Structured form
volumes:
data:
path: /app/data
mount: /mnt/ssd/data # optional — bind to a specific host path, e.g. faster disk
Equivalent to the bind-mount form above, but explicit about which part is the container path and which is the host path — clearer when the paths themselves are long.
What redeploy preserves
On a redeploy, Neo reuses the existing volume for a name it's already seen and only creates new ones for volumes added since the last deploy — so removing a volume from .neo.yml doesn't delete the underlying data, it just stops mounting it. The data stays until you remove it explicitly with neo volumes or Docker directly.
A SQLite gotcha
If your app uses SQLite, the database file itself needs to be inside a declared volume — storage/database.sqlite, not just storage/ in general if the app also writes cache files there you don't want to keep. Be specific about the path that actually needs to survive.
Try it yourself — Neo is free, with every feature unlocked.
Get started free