Skip to main content

arcave savepoint create

Captures a savepoint: every stateful volume, every container's writable layer, the images the services run on, and the compose spec of the project.

Synopsis
arcave savepoint create [name] [flags]

The services are stopped for the capture and started again when it completes — that is what makes the result application-consistent. The sequence is the savepoint flow; what ends up inside is what a savepoint covers.

Everything is captured by default. The capture section of the config turns a kind off for the whole project, and arcave.* labels in the compose file leave out or include a service, a volume, a mount, a layer or an image — see Capture labels. What a savepoint does not hold is listed in its not_covered. When a unit is captured differently than in the latest savepoint, savepoint create warns of it before it stops anything.

Flags​

FlagDefaultDescription
--name—The savepoint's name. Equivalent to the positional argument.
--description—What this savepoint is being taken before.

Neither is a config key: both are per-run values. Global flags apply, and --wait-timeout matters most here — it bounds the health-check wait after the restart.

The name may be a positional argument, --name, or both. Both is an error only when they disagree:

arcave savepoint create before-migration
arcave savepoint create --name before-migration
arcave savepoint create before-migration --name before-migration # fine
arcave savepoint create before-migration --name something-else # savepoint name given both as argument and --name

A savepoint does not need a name. The id is assigned either way.

A name is unique within the compose project and session: savepoint create refuses one another savepoint already carries (safety snapshots aside), one containing /, and one rollback would read as something else — latest, or a savepoint id. All are refused before anything is stopped.

Output​

The savepoint record, as JSON on stdout.

stdout
{
"id": "019e843e-1650-7000-8000-000000000000",
"name": "before-migration",
"description": "before the v2 schema",
"created_at": "2026-06-01T19:41:12.123456789Z",
"stats": [
{
"volume": {
"object_id": "volume-named-myapp_pgdata",
"compose_project": "myapp",
"type": "named",
"backend": "fullcopy",
"named": {
"volume_name": "myapp_pgdata",
"used_by": [
{ "service": "db", "target": "/var/lib/postgresql/data" }
]
}
},
"type": "fullcopy",
"payload": { "size_bytes": 41172480 }
}
],
"writable_layers": [
{
"service": "app",
"replica": 1,
"container_id": "3f1a9c0b2e77…",
"container_name": "myapp-app-1",
"committed_image_id": "sha256:aaaa…",
"imagebackend": "dedupcopy",
"upstream_image_id": "sha256:bbbb…",
"upstream_image_ref": "myapp:latest",
"size_bytes": 83887104,
"stored_bytes": 214016
}
],
"images": [
{
"id": "sha256:bbbb…",
"refs": ["myapp:latest"],
"size_bytes": 83673088,
"stored": true
}
],
"spec": { "format": "compose-yaml" },
"not_covered": {
"services_without_volumes": ["app"]
}
}
FieldMeaning
idA UUIDv7 in canonical form, assigned at capture. What rollback and savepoint remove take.
name, descriptionWhat you passed, or empty strings.
created_atRFC3339Nano.
statsOne entry per captured volume, keyed by volume.object_id — see Storage layout. volume.type is named, bind or anon; volume.backend and type are fullcopy or cdc. payload is the backend's own bookkeeping.
writable_layersOne entry per container whose writable layer was committed. imagebackend is dedupcopy or fullcopy; size_bytes is the committed image's size, stored_bytes what it added to the store after deduplication.
imagesOne entry per distinct image the services run on, stored once however many savepoints and replicas name it. stored_bytes is what this savepoint added, omitted when the image was already stored; stored: false means only its identity could be recorded.
specThe compose spec committed beside the record. format is always compose-yaml.
not_coveredWhat the savepoint does not hold: skipped mounts with a reason code, services with no captured volume, containers killed at the stop deadline, replica gaps, unresolvable images, layers and images a label left out. Omitted when it holds everything. Read it before relying on the savepoint.
labelsPresent only on a safety snapshot.

Each field is omitted when empty, except id, name, description and created_at.

Full shapes for every command are in Output.

Errors​

ConditionWhat happens
The project is not in the Docker daemoncompose project "myapp": no containers found: bring the compose project up once, or name another project with -p
A daemon older than Docker 25unsupported docker daemon: the daemon reports version 24.0.7; arcave needs Docker 25 or newer — before anything is stopped. See Requirements.
An arcave.* label arcave cannot readinvalid capture policy label: arcave.capture="maybe" on service app: want true or false — before anything is stopped. See Capture labels.
A declared named volume the daemon does not holddocker volume "myapp_pgdata" does not exist (bring the project up once to create it). An error, never a skip: an empty capture would silently replace live data at the next rollback.
An anonymous volume whose container is goneno container for service "app" replica 1 in project "myapp" mounts "/data" (is the project created?)
The name is taken in this compose projectsavepoint name is already taken: "before-migration" names savepoint 019e843e-1650-7000-8000-000000000000
The name carries /, is latest or is a savepoint idinvalid savepoint name "feat/v1": must not contain "/", …: is reserved, or …: must not be a savepoint id
The project has no volume to capture, or labels left every one outno stateful volumes found; nothing to capture
Two volumes render one object idtwo volumes address the same object id: service "app" at "/var/lib" and service "app-var" at "/lib" both address "volume-service-app-var-lib"; rename one of them
The savepoint directory already holds objectscapture directory is not empty: 019e843e-1650-7000-8000-000000000000 holds 3 object(s), an interrupted run's remains; check what is there before removing it
A daemon whose version could not be read exports an old archive shapecapturing volumes: … unsupported image archive format: member "…" is neither a blob nor metadata; a daemon older than Docker 25 exports this shape. See Requirements.
An interrupted rollback is markedrollback to savepoint 019e843e-1650-7000-8000-000000000000 was interrupted (restoring) — see Troubleshooting.
Another arcave run holds the lockanother arcave command is already running in this project
The services do not become healthy in --wait-timeoutsavepoint 019e843e-1650-7000-8000-000000000000 committed; services failed to start: … — the savepoint exists and is complete. Only the restart failed: note the id, and look at the project.

An error raised during the capture itself — after the services are stopped — is prefixed capturing volumes: , and the services are started again.

A capture that fails before the record is committed leaves no savepoint. What the failed run wrote is named in the log and left in place; the next capture refuses that directory rather than sweeping it.

Examples​

Before a risky change
arcave savepoint create before-migration --description "pre v2 schema"
Unnamed, in a loop where the id is what matters
ID=$(arcave savepoint create | jq -r .id)
Give a slow project more time to come back
arcave savepoint create before-migration --wait-timeout 5m
Watch a slow capture unfold
arcave --log-level debug savepoint create before-migration

Compose's in-flight steps — Waiting, Starting, Creating, image-pull progress — are logged at debug level.

Next step​

arcave savepoint list — find what you captured.

Tools and expertise for reproducible, production-like environments.
Copyright © 2026 Greenmask, Inc.