# Filesystem-only snapshots (/docs/sandbox/filesystem-only-snapshots)

<!-- agent-signals: reading_time_min: 5 · est_tokens: 2249 · updated: 2026-07-30 -->
Related: [Auto-resume on request](/docs/sandbox/auto-resume.md), [Connect to running sandbox](/docs/sandbox/connect.md), [Environment variables](/docs/sandbox/environment-variables.md), [Sandbox forking](/docs/sandbox/fork.md), [Git integration](/docs/sandbox/git-integration.md), [Monitor sandbox lifecycle events](/docs/sandbox/lifecycle-events-api.md)

When you [pause](/docs/sandbox/persistence) a sandbox, E2B saves a snapshot you
can resume later. By default that snapshot includes **both the filesystem and
the memory**, so resuming restores the sandbox exactly as it was — running
processes and in-memory state included.

A **filesystem-only snapshot** persists only the filesystem. There is no memory
snapshot, so resuming **reboots** the sandbox from its disk: the files on disk
survive, but RAM and running processes do not.

## Full vs. filesystem-only [#full-vs-filesystem-only]

|                                     | Full snapshot (default) | Filesystem-only snapshot |
| ----------------------------------- | ----------------------- | ------------------------ |
| Filesystem (disk)                   | Preserved               | Preserved                |
| Memory (RAM)                        | Preserved               | **Disposed**             |
| Running processes                   | Restored                | **Terminated** (reboot)  |
| In-memory state (variables, caches) | Restored                | **Discarded** (reboot)   |
| Resume behavior                     | Restored in place       | **Reboot** from disk     |
| Speed                               | Baseline                | **Faster**               |

<Note>
  Network connections to clients **outside** the sandbox drop when it pauses — in both cases — and must be re-established on resume (see [Persistence](/docs/sandbox/persistence#network)). The in-sandbox
  difference: a full snapshot keeps the process running so it can serve again immediately, while a filesystem-only snapshot reboots, so the service must be restarted first.
</Note>

Use a filesystem-only snapshot when you only care about the data on disk and don't need running processes restored — for example, persisting a workspace's files between sessions, or checkpointing build/scratch state. The snapshot is lighter to store because there's no memory image, at the cost of a reboot on resume.

## Pause filesystem-only [#pause-filesystem-only]

Pass `keepMemory: false` (JavaScript) / `keep_memory=False` (Python) to `pause()`. The filesystem is saved; memory is dropped.

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```js highlight={6}  
      import { Sandbox } from 'e2b'

      const sbx = await Sandbox.create()

      // Save only the filesystem — resuming will reboot the sandbox
      await sbx.pause({ keepMemory: false })

      // Resume: the sandbox reboots from disk (files survive, processes do not)
      const sameSbx = await sbx.connect()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python highlight={6}  
      from e2b import Sandbox

      sbx = Sandbox.create()

      # Save only the filesystem — resuming will reboot the sandbox
      sbx.pause(keep_memory=False)

      # Resume: the sandbox reboots from disk (files survive, processes do not)
      same_sbx = sbx.connect()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

`keepMemory` / `keep_memory` defaults to `true`, so omitting it (or calling `pause()`) takes a full memory snapshot — see [Persistence](/docs/sandbox/persistence).

`keepMemory` is a per-pause choice, not a sandbox-wide mode. Pausing once with `keepMemory: false` / `keep_memory=False` does not lock the sandbox into filesystem-only: after you resume, the next `pause()` takes a full memory snapshot again unless you pass `keepMemory: false` / `keep_memory=False` once more.

## Auto-pause filesystem-only [#auto-pause-filesystem-only]

You can also make the timeout-driven [auto-pause](/docs/sandbox/persistence#auto-pause) filesystem-only. Set `onTimeout` / `on_timeout` to the object form and include `keepMemory` / `keep_memory`:

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```js highlight={5}  
      import { Sandbox } from 'e2b'

      const sandbox = await Sandbox.create({
        lifecycle: {
          onTimeout: { action: 'pause', keepMemory: false },
        },
      })
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python highlight={5}  
      from e2b import Sandbox

      sandbox = Sandbox.create(
          lifecycle={
              "on_timeout": {"action": "pause", "keep_memory": False},
          },
      )
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

When this sandbox times out, it auto-pauses filesystem-only; the next explicit resume reboots it. See [Auto-resume on request](/docs/sandbox/auto-resume) for the full `lifecycle` reference.

## Type safety and validation [#type-safety-and-validation]

`keepMemory` / `keep_memory` only governs a `pause` action, so the SDK rejects nonsensical combinations:

* It cannot be set when the action is `kill`. In TypeScript this is a **compile-time type error** (the `onTimeout` object is a discriminated union on `action`); in Python it raises `InvalidArgumentException`.
* It cannot be combined with **auto-resume**. A filesystem-only snapshot can't be woken by inbound traffic (auto-resume restores the running process from memory, which a filesystem-only snapshot doesn't have), so it must be resumed explicitly with [`connect()`](/docs/sandbox/connect). Setting `keepMemory: false` / `keep_memory=False` together with `autoResume: true` / `auto_resume=True` is rejected client-side.

<Warning>
  A filesystem-only snapshot is **not** compatible with auto-resume. Resume it explicitly via `connect()` — it will not wake on traffic.
</Warning>

## What changes on resume [#what-changes-on-resume]

Resuming a filesystem-only snapshot is a reboot, so it takes roughly a fresh
boot rather than the near-instant in-place memory restore. Any service running
inside the sandbox must be restarted after resume, and clients must reconnect.

Because resume is a reboot, anything that lived only in memory is gone, while
everything written to disk persists. The example below writes a file and starts
a background process, pauses filesystem-only, then resumes: the file is still
there, but the process is not.

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```js  
      import { Sandbox } from 'e2b'

      const sbx = await Sandbox.create()

      await sbx.files.write('/home/user/data.txt', 'survives the reboot')
      const cmd = await sbx.commands.run('sleep 600', { background: true })

      await sbx.pause({ keepMemory: false })
      const resumed = await sbx.connect()

      // File on disk survives the reboot
      const content = await resumed.files.read('/home/user/data.txt')
      console.log(content) // "survives the reboot"

      // The background process is gone — the sandbox rebooted
      const check = await resumed.commands.run(`kill -0 ${cmd.pid}`, { background: false })
      console.log(check.exitCode !== 0) // true — process no longer running
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python  
      from e2b import Sandbox

      sbx = Sandbox.create()

      sbx.files.write("/home/user/data.txt", "survives the reboot")
      cmd = sbx.commands.run("sleep 600", background=True)

      sbx.pause(keep_memory=False)
      resumed = sbx.connect()

      # File on disk survives the reboot
      content = resumed.files.read("/home/user/data.txt")
      print(content)  # "survives the reboot"

      # The background process is gone — the sandbox rebooted
      check = resumed.commands.run(f"kill -0 {cmd.pid}", background=False)
      print(check.exit_code != 0)  # True — process no longer running
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Related [#related]

* [Sandbox persistence](/docs/sandbox/persistence) — full (memory + filesystem) pause and resume.
* [Auto-resume on request](/docs/sandbox/auto-resume) — the full `lifecycle` configuration reference.
* [Connect to a sandbox](/docs/sandbox/connect) — resume a paused sandbox explicitly.
