Most apps do not need a volume. Use
/shared.db and /shared/ for state shared across
instances and regions.
A persistent volume is a private filesystem for software that expects local disk, such as Postgres, Redis, or a development environment. Attaching one makes the service stable: its identity and disk remain together across deploys, restarts, and host moves.
attach a volume
Attach a volume to an automatic source build:
kedge up --volume /var/lib/myapp --volume-size 20GiB
For a prebuilt image:
kedge publish my-database --image postgres:18 \
--volume /var/lib/postgresql/data \
--volume-size 20GiB
size is a sparse logical limit. The volume is seeded from the image path on
first boot.
Dockerfiles and images
A Dockerfile VOLUME creates a one-member app by default:
VOLUME ["/var/lib/postgresql/data"]
Use --members 0 when an image declares a volume the service does not need:
kedge publish myapp --image example/myapp:1.2 --members 0
Several volume paths for one member share its underlying store while remaining
separate directories. Dockerfile and image volume declarations seed those
paths unless volume.nocopy is set.
Compose
Use a named volume for a service in a Compose app:
services:
db:
image: postgres:18
volumes: [data:/var/lib/postgresql/data]
volumes:
data:
x-kedge:
shared: false
size: 20GiB
shared: false gives each stable member its own persistent volume. A
shared: true volume mounts
the app's replicated /shared/ tree instead.
With a persistent volume, deploy.replicas sets the member count. Outside
Compose, use --members:
kedge up --volume /data --members 3
stable members
Kedge calls each stable copy of a service a member. Members have ordinals starting at zero:
<ordinal>.<service>.<app>.internalreaches one member.<service>.<app>.internalreaches the member set.
Each member has its own volume. Scaling down retains that volume; scaling up reattaches the same ordinal.
List members or move one to another region:
kedge members my-database
kedge members my-database migrate 0 nrt
Kedge handles ordinary restarts and host recovery automatically.
durability
Volume flushes use the host's local disk (NVMe on production hosts). fsync,
ext4 journal commits, and database checkpoints do not wait for object storage.
Kedge publishes local writes to object storage in the background after 1s or 16 MiB. A controlled stop, member migration, or fork waits until every accepted write is published before it proceeds. If object storage is unavailable, that operation fails and leaves the member in place.
The local writeback limit is 4 GiB per volume by default. If publication cannot keep up and the limit fills, new writes fail instead of consuming unbounded host memory. Restarting the daemon on the same host replays the local journal. After complete host loss, recovery uses the last published remote state.
Check publication state:
kedge volumes status my-database-0
clean means every write accepted by the volume backend is present in the
remote manifest. It does not include data still held in the guest filesystem's
page cache. Other states report pending writes, object-store errors, lease
fencing, or a full local journal.
retention and deletion
Member volumes are named <app>-<ordinal> and never disappear as a side
effect. App deletion, service removal, or scale-down leaves them retained.
List and explicitly delete retained volumes:
kedge volumes
kedge volumes rm my-database-0
Attached volumes and ancestors still used by forks refuse deletion. The generated REST volume operations expose the same operations.