diff --git a/src/content/changelog/containers/2026-03-26-snapshots.mdx b/src/content/changelog/containers/2026-03-26-snapshots.mdx
new file mode 100644
index 00000000000000..d746dfb485dcee
--- /dev/null
+++ b/src/content/changelog/containers/2026-03-26-snapshots.mdx
@@ -0,0 +1,72 @@
+---
+title: Snapshot and restore Container state
+description: Persist point-in-time container filesystem with experimental snapshot APIs.
+products:
+ - containers
+date: 2026-03-26
+---
+
+import { TypeScriptExample, WranglerConfig } from "~/components";
+
+[Containers](/containers/) now support experimental snapshot APIs for saving and restoring point-in-time filesystem state. Create a snapshot first, then pass it back to `start()` to restore files after container sleep, restart, or handoff to another Durable Object.
+
+Turn on the `experimental` [compatibility flag](/workers/configuration/compatibility-flags/) before you use snapshot APIs:
+
+
+
+```toml
+compatibility_flags = ["experimental"]
+```
+
+
+
+You can snapshot a single directory with `snapshotDirectory()` or the full container with `snapshotContainer()`. The example uses the [Container class](/containers/container-package/). Create snapshots from a container that is already running:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async saveSnapshots() {
+ const directorySnapshot = await this.ctx.container.snapshotDirectory({
+ dir: "/app/foo",
+ });
+
+ const containerSnapshot = await this.ctx.container.snapshotContainer({});
+
+ await this.ctx.storage.put("directorySnapshot", directorySnapshot);
+ await this.ctx.storage.put("containerSnapshot", containerSnapshot);
+ }
+}
+```
+
+
+
+Later, if you saved both snapshot types, load the saved snapshot handles and restore them with `start()`:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async restoreSnapshots() {
+ const directorySnapshot =
+ await this.ctx.storage.get("directorySnapshot");
+ const containerSnapshot =
+ await this.ctx.storage.get("containerSnapshot");
+
+ this.ctx.container.start({
+ containerSnapshot,
+ directorySnapshots: [{ snapshot: directorySnapshot }],
+ });
+ }
+}
+```
+
+
+
+Snapshots are immutable. Directory snapshots can be restored to a different `mountPoint`. You can restore multiple directory snapshots in one `start()` call, but only one container snapshot.
+
+For more information, refer to [Snapshots](/containers/platform-details/snapshots/) and [Durable Object Container](/durable-objects/api/container/).
diff --git a/src/content/docs/containers/faq.mdx b/src/content/docs/containers/faq.mdx
index 071b2d44f65c44..38e4919825d770 100644
--- a/src/content/docs/containers/faq.mdx
+++ b/src/content/docs/containers/faq.mdx
@@ -89,11 +89,9 @@ See [image management documentation](/containers/platform-details/image-manageme
## Is disk persistent? What happens to my disk when my container sleeps?
-All disk is ephemeral. When a Container instance goes to sleep, the next time
-it is started, it will have a fresh disk as defined by its container image.
+All disk is ephemeral by default. When a Container instance goes to sleep, the next time it starts, it uses a fresh disk from the container image.
-Persistent disk is something the Cloudflare team is exploring in the future, but
-is not slated for the near term.
+If you need point-in-time filesystem state, create and restore an experimental snapshot. Snapshots are immutable, so later file changes require a new snapshot. For more information, refer to [Snapshots](/containers/platform-details/snapshots/).
## What happens if I run out of memory?
diff --git a/src/content/docs/containers/platform-details/architecture.mdx b/src/content/docs/containers/platform-details/architecture.mdx
index c970c73cb10860..b0768f736ea789 100644
--- a/src/content/docs/containers/platform-details/architecture.mdx
+++ b/src/content/docs/containers/platform-details/architecture.mdx
@@ -98,12 +98,11 @@ When a container instance is going to be shut down, it is sent a `SIGTERM` signa
and then a `SIGKILL` signal after 15 minutes. You should perform any necessary
cleanup to ensure a graceful shutdown in this time.
-#### Persistent disk
+#### Use snapshots
-All disk is ephemeral. When a Container instance goes to sleep, the next time
-it is started, it will have a fresh disk as defined by its container image.
-Persistent disk is something the Cloudflare team is exploring in the future, but
-is not slated for the near term.
+All disk is ephemeral by default. When a Container instance goes to sleep, the next time it starts, it uses a fresh disk from the container image.
+
+If you need point-in-time filesystem state, create and restore an experimental snapshot. Snapshots are immutable, so later file changes require a new snapshot. For more information, refer to [Snapshots](/containers/platform-details/snapshots/).
## An example request
diff --git a/src/content/docs/containers/platform-details/snapshots.mdx b/src/content/docs/containers/platform-details/snapshots.mdx
new file mode 100644
index 00000000000000..4c8d61a4159fc9
--- /dev/null
+++ b/src/content/docs/containers/platform-details/snapshots.mdx
@@ -0,0 +1,181 @@
+---
+title: Use snapshots
+pcx_content_type: how-to
+sidebar:
+ order: 55
+description: Persist container filesystem across restarts.
+---
+
+import { TypeScriptExample, WranglerConfig } from "~/components";
+
+Snapshots let you save point-in-time filesystem state from a running [Container](/containers/). The examples on this page use the [Container class](/containers/container-package/).
+
+:::caution[Experimental]
+Snapshot APIs require the `experimental` [compatibility flag](/workers/configuration/compatibility-flags/). These APIs may change in backward-incompatible ways.
+:::
+
+## Turn on the compatibility flag
+
+Add `experimental` to your Worker's Wrangler configuration before you use snapshot APIs:
+
+
+
+```toml
+compatibility_date = "$today"
+compatibility_flags = ["experimental"]
+```
+
+
+
+## Choose a snapshot type
+
+Use `snapshotDirectory()` to capture one directory. Use `snapshotContainer()` to capture the full container filesystem.
+
+Both snapshot types are immutable. If you restore a snapshot and then change files, create a new snapshot to persist those changes.
+
+- You can restore multiple directory snapshots in one `start()` call.
+- You can restore only one container snapshot in one `start()` call.
+- You can restore directory snapshots on top of a container snapshot.
+- Snapshot handles are plain data objects, so you can store them and restore them later, even from another Durable Object.
+
+## Create a directory snapshot
+
+Use `snapshotDirectory()` to capture the current contents of a directory in a running container:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async saveWorkspace() {
+ return await this.ctx.container.snapshotDirectory({
+ dir: "/app/workspace",
+ name: "workspace-checkpoint",
+ });
+ }
+}
+```
+
+
+
+The `dir` value must be an absolute path. The API returns a serializable snapshot handle that you can store and restore later.
+
+## Create a container snapshot
+
+Use `snapshotContainer()` to capture the full container filesystem:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async saveContainer() {
+ return await this.ctx.container.snapshotContainer({
+ name: "before-upgrade",
+ });
+ }
+}
+```
+
+
+
+The API returns a serializable snapshot handle that you can store and restore later.
+
+## Restore snapshots
+
+First, create snapshots from a container that is already running. You can store the returned handles in Durable Object storage and use them later:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async saveSnapshots() {
+ const directorySnapshot = await this.ctx.container.snapshotDirectory({
+ dir: "/app/foo",
+ });
+
+ const containerSnapshot = await this.ctx.container.snapshotContainer({});
+
+ await this.ctx.storage.put("directorySnapshot", directorySnapshot);
+ await this.ctx.storage.put("containerSnapshot", containerSnapshot);
+ }
+}
+```
+
+
+
+Later, if you saved both snapshot types, load the saved snapshot handles and pass them to `this.ctx.container.start()` when you start another container:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async restoreSnapshots() {
+ const directorySnapshot =
+ await this.ctx.storage.get("directorySnapshot");
+ const containerSnapshot =
+ await this.ctx.storage.get("containerSnapshot");
+
+ this.ctx.container.start({
+ containerSnapshot,
+ directorySnapshots: [{ snapshot: directorySnapshot }],
+ });
+ }
+}
+```
+
+
+
+If you do not set `mountPoint`, the directory snapshot is restored to the same path that was snapshotted. You can also restore it to a different path:
+
+
+
+```ts
+import { Container } from "@cloudflare/containers";
+
+export class MyContainer extends Container {
+ async restoreWorkspaceSnapshot() {
+ const directorySnapshot =
+ await this.ctx.storage.get("directorySnapshot");
+
+ if (!directorySnapshot) {
+ return;
+ }
+
+ this.ctx.container.start({
+ directorySnapshots: [
+ {
+ snapshot: directorySnapshot,
+ mountPoint: "/app/restored-workspace",
+ },
+ ],
+ });
+ }
+}
+```
+
+
+
+## Understand restore behavior
+
+- Directory snapshots cannot be restored to `/`.
+- You can snapshot `/`, but you must restore it to a subdirectory by setting `mountPoint`.
+- Nested directory snapshots restore in depth order. If you restore snapshots to `/app` and `/app/data`, `/app` is always restored first.
+- Directory snapshots can overlay files from a container snapshot.
+
+## Understand retention
+
+Snapshots currently have an implicit 90-day time-to-live. Each restore refreshes that time-to-live.
+
+You cannot set a custom time-to-live yet.
+
+## Related resources
+
+- [Durable Object Container](/durable-objects/api/container/) - Full `ctx.container` API reference
+- [Lifecycle of a Container](/containers/platform-details/architecture/) - Understand startup, sleep, and shutdown behavior
diff --git a/src/content/docs/durable-objects/api/container.mdx b/src/content/docs/durable-objects/api/container.mdx
index 614ef1634b3a8e..0c052b119eeb0d 100644
--- a/src/content/docs/durable-objects/api/container.mdx
+++ b/src/content/docs/durable-objects/api/container.mdx
@@ -13,6 +13,7 @@ import {
Type,
MetaInfo,
TypeScriptExample,
+ WranglerConfig,
} from "~/components";
## Description
@@ -20,6 +21,18 @@ import {
When using a [Container-enabled Durable Object](/containers), you can access the Durable Object's associated container via
the `container` object which is on the `ctx` property. This allows you to start, stop, and interact with the container.
+:::caution[Experimental snapshot APIs]
+`snapshotDirectory()`, `snapshotContainer()`, `directorySnapshots`, and `containerSnapshot` require the `experimental` [compatibility flag](/workers/configuration/compatibility-flags/). These APIs may change in backward-incompatible ways.
+
+
+
+```toml
+compatibility_flags = ["experimental"]
+```
+
+
+:::
+
:::note
It is likely preferable to use the official `Container` class, which provides helper methods and
a more idiomatic API for working with containers on top of Durable Objects.
@@ -76,11 +89,83 @@ this.ctx.container.start({
- `env`: An object containing environment variables to pass to the container. This is useful for passing configuration values or secrets to the container.
- `entrypoint`: An array of strings representing the command to run in the container.
- `enableInternet`: A boolean indicating whether to enable internet access for the container.
+ - `directorySnapshots`: An array of objects describing directory snapshots to restore before the container starts. You can restore more than one directory snapshot in a single call.
+ - `snapshot`: The `ContainerDirectorySnapshot` to restore.
+ - `mountPoint` (optional): The absolute path where the snapshot is restored. If omitted, the snapshot is restored to its original `dir` path.
+ - `containerSnapshot`: A full container snapshot to restore before the container starts. You can restore only one container snapshot in a single call.
#### Return values
- None.
+#### Understand snapshot restore behavior
+
+- Directory snapshots are restored before the container starts.
+- If `mountPoint` is not set, the snapshot is restored to the original `dir` path.
+- Directory snapshots cannot be restored to `/`.
+- You can snapshot `/`, but that snapshot must be restored to a subdirectory by setting `mountPoint`.
+- Nested directory snapshots are restored in depth order. For example, `/app` is restored before `/app/data`.
+- Directory snapshots can be restored on top of a container snapshot.
+
+### `snapshotDirectory`
+
+`snapshotDirectory` creates a point-in-time snapshot of a directory in a running container.
+
+
+
+```ts
+const snapshot = await this.ctx.container.snapshotDirectory({
+ dir: "/app/workspace",
+ name: "workspace-checkpoint",
+});
+```
+
+
+
+#### Parameters
+
+- `options`: An object with the following properties:
+ - `dir` (string): An absolute path for the directory to snapshot.
+ - `name` (optional string): A human-friendly name for the snapshot.
+
+#### Return values
+
+- A promise that resolves to a `ContainerDirectorySnapshot` object with `id`, `size`, `dir`, and optional `name` properties.
+
+#### Notes
+
+- Snapshots are immutable. If you change restored files, create a new snapshot to persist those changes.
+- You can serialize the returned snapshot handle and restore it later, including from another Durable Object.
+- Snapshot handles currently have an implicit 90-day time-to-live that refreshes when you restore them.
+
+### `snapshotContainer`
+
+`snapshotContainer` creates a point-in-time snapshot of the full running container filesystem.
+
+
+
+```ts
+const snapshot = await this.ctx.container.snapshotContainer({
+ name: "before-upgrade",
+});
+```
+
+
+
+#### Parameters
+
+- `options`: An object with the following properties:
+ - `name` (optional string): A human-friendly name for the snapshot.
+
+#### Return values
+
+- A promise that resolves to a `ContainerSnapshot` object with `id`, `size`, and optional `name` properties.
+
+#### Notes
+
+- Container snapshots are immutable.
+- Snapshot handles currently have an implicit 90-day time-to-live that refreshes when you restore them.
+
### `destroy`
`destroy` stops the container and optionally returns a custom error message to the `monitor()` error callback.
@@ -207,6 +292,7 @@ await this.ctx.container.interceptOutboundHttp("123.123.123.123/23", worker);
`interceptAllOutboundHttp` routes all outbound HTTP requests from the container through a `WorkerEntrypoint`, regardless of destination.
await this.ctx.container.interceptAllOutboundHttp(worker);
+
```
#### Parameters
@@ -229,3 +315,5 @@ await this.ctx.container.interceptAllOutboundHttp(worker);
- [Containers](/containers)
- [Get Started With Containers](/containers/get-started)
+- [Snapshots](/containers/platform-details/snapshots/)
+```