Snapshots
Take a snapshot of a workspace or an environment to add it to the lineage of its volume.
Last updated
On this page
Description and operation
General
A snapshot is a saved, read-only copy of a workspace or an environment at one time. It holds the files of the disk and the definition of its source. You push a snapshot to save one. Each push adds one snapshot to the lineage of the volume of its source. The new snapshot names the snapshot before it as its parent. For a push after a restore, see Restore and clone.
before the push: backend-base@2 ← backend-base@1after the push: backend-base@3 ← backend-base@2 ← backend-base@1 "before the refactor"Later you restore a workspace or an environment from a snapshot. A clone is not a snapshot: it copies the live state of a workspace or an environment.
A snapshot stays when its workspace or environment is deleted. The snapshots of one source are kept on one volume. The first push names the volume. See Names and versions.
The platform shows no size for one snapshot. The volume shows the disk that it uses with all its snapshots. For the parts of a snapshot, see Lineage.
A snapshot belongs to the owner of its source. A snapshot of a team workspace or a team environment counts against the quota of the team. You read the snapshots of your own volumes and of the volumes of your teams.
To do these tasks with an AI agent, see Agentic workflows – Volumes.
Snapshot types
The source sets the type of a snapshot. The type sets what the snapshot freezes and how you use it.
| Aspect | Workspace snapshot | Environment snapshot |
|---|---|---|
| Made with | Push a snapshot of a workspace | Push a snapshot of an environment |
| Files | The home of the workspace | The data folders of all services |
Frozen in state | image, packages, locks, resources, quotaGb | services, quotaGb |
| Not frozen | Variables, the session, extra working directories | Intercepts, the sessions that connect to it |
| Makes a new workspace or environment | Restore a workspace | Clone an environment from a snapshot |
| Puts the source back | No | Restore an environment |
A workspace snapshot cannot make an environment, and an environment snapshot cannot make a workspace.
Snapshot parameters
A request to push a snapshot has a body. A request with no body is valid after the volume has a name.
| Parameter | Required | Description |
|---|---|---|
message | No | A note for the history. |
ttl_secs | No | The lifetime in seconds, 3600 to 31536000. See Lifecycle. |
never | No | true keeps the snapshot with no expiry. Do not give it with ttl_secs. |
volume | On the first push | The name of the volume. The first push of a volume must give it. Later pushes can omit it. When given, it must equal the name. |
The answer is 202 with id, phase, volume, name, version and expires_at. volume is the volume id. name and version are the volume name and the number of this push. expires_at is null when never is true. Only the versions list of a named volume shows expires_at later.
States
phase | Meaning |
|---|---|
pending | The request is accepted. It did not start. |
working | The snapshot is being made. A second snapshot of the same workspace or environment is refused. |
ready | The snapshot is complete. You can restore, clone and delete it. |
error | The snapshot failed. The snapshot is not usable. |
Lifecycle
- Push. A push is the only operation that makes a snapshot.
- Sync points. Between snapshots, the platform keeps internal copies of each running workspace and environment. These sync points are not snapshots. They are never listed, are not a restore target and cannot be deleted by hand.
- Expiry. A snapshot lives for the region default, 30 days, unless the request gives
ttl_secsornever. An administrator can change the default. - Use. A restore or a clone from a snapshot moves its expiry to a full default lifetime from now. An expiry never becomes shorter.
- Expired snapshots. Every 10 minutes the platform deletes expired snapshots, with the rules of a delete by hand. The platform keeps a snapshot that a running workspace or environment uses, or that a pipeline reads.
- Source deleted. A snapshot stays when its workspace or environment is deleted. The volume then stays too, detached, so that you can restore from it.
- Delete. You delete one snapshot at a time, as in Delete a snapshot from the lineage.
Quota and limits
Two quota dimensions apply to snapshots. See Quota and requests.
| Item | Limit |
|---|---|
snapshots | The number of snapshots of the owner. Each snapshot counts one. Sync points do not count. |
diskGb | The disk of all volumes of the owner, also detached volumes. A new snapshot is refused when the disk is already above the limit. |
ttl_secs | 3600 to 31536000 seconds. |
| Snapshots in progress | One for each workspace or environment. |
Tasks
Push a snapshot of a workspace
Reason for the task: Save the files and the definition of a workspace in a snapshot.
Job set-up
- Access: you. A team workspace needs team membership.
- References:
POST /v1/workspaces/{id}/snapshots.
Procedure
Push a snapshot of the workspace. Give a note in
messageand a name involume.snap = kl.workspaces.take_snapshot(workspace="backend", message="before the refactor", volume="backend-base")print(snap["id"], snap["phase"], snap["expires_at"])const snap = (await kl.workspaces.takeSnapshot({ workspace: "backend", message: "before the refactor", volume: "backend-base" })) as Record<string, unknown>;console.log(snap.id, snap.phase, snap.expires_at);snap, err := kl.Workspaces.TakeSnapshot(kloudlite.TakeWorkspaceSnapshot{Workspace: "backend", Message: "before the refactor", Volume: "backend-base"})if err != nil { log.Fatal(err)}fmt.Println(snap["id"], snap["phase"], snap["expires_at"])snap = kl.workspaces.take_snapshot(workspace: "backend", message: "before the refactor", volume: "backend-base")puts snap.values_at("id", "phase", "expires_at").join(" ")// The SDK returns the answer as raw JSON. Read the fields with your own JSON library.String snap = kl.workspaces().takeSnapshot(new Kloudlite.TakeWorkspaceSnapshot().workspace("backend").message("before the refactor").volume("backend-base"));System.out.println(snap);kloudlite snapshots push --workspace backend --message "before the refactor" --volume backend-baseSend
ttl_secsorneverin a raw request in place of step 1, to set the lifetime.ws = kl.workspaces.get(workspace="backend")kl.request("POST", f"/v1/workspaces/{ws['id']}/snapshots", body={"ttl_secs": 604800})const ws = (await kl.workspaces.get({ workspace: "backend" })) as { id: string };await kl.request("POST", `/v1/workspaces/${ws.id}/snapshots`, { ttl_secs: 604800 });ws, err := kl.Workspaces.Get("backend")if err != nil { log.Fatal(err)}err = kl.Request("POST", fmt.Sprintf("/v1/workspaces/%v/snapshots", ws["id"]), kloudlite.RequestOptions{ Body: map[string]any{"ttl_secs": 604800},})if err != nil { log.Fatal(err)}ws = kl.workspaces.get(workspace: "backend")kl.request("POST", "/v1/workspaces/#{ws['id']}/snapshots", body: { ttl_secs: 604800 })// The path takes the name of the workspace in place of its id.kl.request(new Kloudlite.RawRequest() .method("POST") .path("/v1/workspaces/backend/snapshots") .body("{\"ttl_secs\":604800}"));kloudlite request POST /v1/workspaces/ws-0a1b2c3d4e5f6a7b/snapshots --body '{"ttl_secs": 604800}'
Close-out
- Show the lineage, as in Show the lineage. Make sure that the first row shows your note and the
phaseready.
Push a snapshot of an environment
Reason for the task: Save the services and the data of an environment in a snapshot.
Job set-up
- Access: you. A team environment needs team membership.
- References:
POST /v1/environments/{id}/snapshots.
Procedure
Push a snapshot of the environment. Use
team/namefor a team environment, and givevolume.snap = kl.environments.take_snapshot(environment="acme/dev", message="before the schema change", volume="dev-data")print(snap["id"], snap["phase"], snap["expires_at"])const snap = (await kl.environments.take_snapshot({ environment: "acme/dev", message: "before the schema change", volume: "dev-data" })) as Record<string, unknown>;console.log(snap.id, snap.phase, snap.expires_at);snap, err := kl.Environments.TakeSnapshot(kloudlite.TakeEnvironmentSnapshot{Environment: "acme/dev", Message: "before the schema change", Volume: "dev-data"})if err != nil { log.Fatal(err)}fmt.Println(snap["id"], snap["phase"], snap["expires_at"])snap = kl.environments.take_snapshot(environment: "acme/dev", message: "before the schema change", volume: "dev-data")puts snap.values_at("id", "phase", "expires_at").join(" ")// The SDK returns the answer as raw JSON. Read the fields with your own JSON library.String snap = kl.environments().takeSnapshot(new Kloudlite.TakeEnvironmentSnapshot().environment("acme/dev").message("before the schema change").volume("dev-data"));System.out.println(snap);kloudlite snapshots push --environment acme/dev --message "before the schema change" --volume dev-data
Close-out
- Show the lineage, as in Show the lineage. Make sure that the first row shows your note and the
phaseready.
Troubleshooting
| Symptom | Possible cause | Corrective action |
|---|---|---|
409 with snapshots: 20 of 20 in use; request more under Quota | The owner used all the snapshots of the quota. The numbers are examples. | Delete a snapshot, or request more quota. |
409 with diskGb: 120 of 100 in use; request more under Quota | The disk of the owner is above the quota. | Delete snapshots or volumes that you do not need. |
409 with a snapshot is already being cut for this workspace | An earlier snapshot or clone of the same source is in progress. | Wait until its phase is ready, then push the snapshot again. |
409 with not ready yet: no volume for this workspace | The workspace or the environment has no disk yet. | Wait until it is ready, then push the snapshot again. |
422 with volume: this volume has no name yet; name it on its first push | The volume has no name, and the push gave no volume. | Push again with volume. See Volumes. |
422 with volume go-base: … | The name breaks the name rule. | Use 1 to 40 characters of a-z, 0-9 and -. |
409 with volume go-base already exists; delete it first | Another volume of the owner has this name. | Use a different name, or delete the other volume. |
409 with this volume is named go-base, not other | volume differs from the name of the volume. | Leave out volume, or give the name of the volume. |
409 with the version counter of go-base is busy; retry | Many pushes of the volume ran at the same time. | Push again. |
400 with invalid snapshot body | The body is not valid JSON, or a field has the wrong type. | Send a JSON object with only the snapshot parameters. |
400 with ttl_secs and never are exclusive | The request gives ttl_secs and never. | Give one of them. |
422 with ttl_secs must be between 3600 and 31536000 | ttl_secs is out of range. | Give a value in the range. |
404 with the volume this worktree is on no longer exists | The volume of the source was deleted. | Show the status of the source. Push the snapshot again when it has a volume. |