# Sandbox persistence (/docs/sandbox/persistence)

<!-- agent-signals: reading_time_min: 8 · est_tokens: 3531 · 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), [Filesystem-only snapshots](/docs/sandbox/filesystem-only-snapshots.md), [Sandbox forking](/docs/sandbox/fork.md), [Git integration](/docs/sandbox/git-integration.md)

The sandbox persistence allows you to pause your sandbox and resume it later from the same state it was in when you paused it.

This includes not only state of the sandbox's filesystem but also the sandbox's memory. This means all running processes, loaded variables, data, etc.

## Sandbox state transitions [#sandbox-state-transitions]

Understanding how sandboxes transition between different states is crucial for managing their lifecycle effectively. Here's a diagram showing the possible state transitions:

```mermaid actions={false}
flowchart TD
    start(( )) -->|Sandbox.create| Running

    Running["<b>Running</b><br/>• Active execution<br/>• Consumes resources"]
    Paused["<b>Paused</b><br/>• Preserves memory and files<br/>• Cannot execute code"]
    Snapshotting["<b>Snapshotting</b><br/>• Creates persistent snapshot<br/>• Briefly pauses execution"]
    Killed["<b>Killed</b><br/>• Resources released<br/>• Cannot be resumed"]

    Running -->|pause| Paused
    Running -->|createSnapshot| Snapshotting
    Paused -->|connect| Running
    Snapshotting -->|snapshot complete| Running
    Running -->|kill| Killed
    Paused -->|kill| Killed
```

### State descriptions [#state-descriptions]

* **Running**: The sandbox is actively running and can execute code. This is the initial state after creation.
* **Paused**: The sandbox execution is suspended but its state is preserved.
* **Snapshotting**: The sandbox is briefly paused while a persistent snapshot is being created. It automatically returns to Running. See [Snapshots](/docs/sandbox/snapshots).
* **Killed**: The sandbox is terminated and all resources are released. This is a terminal state.

### Changing sandbox's state [#changing-sandboxs-state]

<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 sandbox = await Sandbox.create() // Starts in Running state

      // Pause the sandbox
      await sandbox.pause() // Running → Paused

      // Resume the sandbox
      await sandbox.connect() // Running/Paused → Running

      // Kill the sandbox (from any state)
      await sandbox.kill() // Running/Paused → Killed
      ```
    </CodeBlockTab>

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

      sandbox = Sandbox.create()  # Starts in Running state

      # Pause the sandbox
      sandbox.pause()  # Running → Paused

      # Resume the sandbox
      sandbox.connect()  # Running/Paused → Running

      # Kill the sandbox (from any state)
      sandbox.kill()  # Running/Paused → Killed
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Pausing sandbox [#pausing-sandbox]

When you pause a sandbox, both the sandbox's filesystem and memory state will be saved. This includes all the files in the sandbox's filesystem and all the running processes, loaded variables, data, etc.

<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={8-9}  
      import { Sandbox } from 'e2b'

      const sbx = await Sandbox.create()
      console.log('Sandbox created', sbx.sandboxId)

      // Pause the sandbox
      // You can save the sandbox ID in your database to resume the sandbox later
      await sbx.pause()
      console.log('Sandbox paused', sbx.sandboxId)
      ```
    </CodeBlockTab>

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

      sbx = Sandbox.create()
      print('Sandbox created', sbx.sandbox_id)

      # Pause the sandbox
      # You can save the sandbox ID in your database to resume the sandbox later
      sbx.pause()
      print('Sandbox paused', sbx.sandbox_id) 
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

By default a pause saves **both** the filesystem and the memory. To save only the filesystem — a lighter snapshot that cold-boots (reboots) on resume — pass `keepMemory: false` (JavaScript) / `keep_memory=False` (Python). See [Filesystem-only snapshots](/docs/sandbox/filesystem-only-snapshots).

## Resuming sandbox [#resuming-sandbox]

When you resume a sandbox, it will be in the same state it was in when you paused it.
This means that all the files in the sandbox's filesystem will be restored and all the running processes, loaded variables, data, etc. will be restored.

<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={12-13}  
      import { Sandbox } from 'e2b'

      const sbx = await Sandbox.create()
      console.log('Sandbox created', sbx.sandboxId)

      // Pause the sandbox
      // You can save the sandbox ID in your database to resume the sandbox later
      await sbx.pause()
      console.log('Sandbox paused', sbx.sandboxId)

      // Connect to the sandbox (it will automatically resume the sandbox, if paused)
      const sameSbx = await sbx.connect()
      console.log('Connected to the sandbox', sameSbx.sandboxId)
      ```
    </CodeBlockTab>

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

      sbx = Sandbox.create()
      print('Sandbox created', sbx.sandbox_id)

      # Pause the sandbox
      # You can save the sandbox ID in your database to resume the sandbox later
      sbx.pause()
      print('Sandbox paused', sbx.sandbox_id)

      # Connect to the sandbox (it will automatically resume the sandbox, if paused)
      same_sbx = sbx.connect()
      print('Connected to the sandbox', same_sbx.sandbox_id)
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Listing paused sandboxes [#listing-paused-sandboxes]

You can list all paused sandboxes by calling the `Sandbox.list` method and supplying the `state` query parameter.
More information about using the method can be found in [List Sandboxes](/docs/sandbox/list).

<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={4,7}  
      import { Sandbox, SandboxInfo } from 'e2b'

      // List all paused sandboxes
      const paginator = Sandbox.list({ query: { state: ['paused'] } })

      // Get the first page of paused sandboxes
      const sandboxes = await paginator.nextItems()

      // Get all paused sandboxes
      while (paginator.hasNext) {
        const items = await paginator.nextItems()
        sandboxes.push(...items)
      }
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python highlight={4,7}  
      # List all paused sandboxes
      from e2b import Sandbox, SandboxQuery, SandboxState

      paginator = Sandbox.list(SandboxQuery(state=[SandboxState.PAUSED]))

      # Get the first page of paused sandboxes
      sandboxes = paginator.next_items()

      # Get all paused sandboxes
      while paginator.has_next:
        items = paginator.next_items()
        sandboxes.extend(items)
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Removing paused sandboxes [#removing-paused-sandboxes]

You can remove paused sandboxes by calling the `kill` method on the Sandbox instance.

<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={11,14}  
      import { Sandbox } from 'e2b'

      const sbx = await Sandbox.create()
      console.log('Sandbox created', sbx.sandboxId)

      // Pause the sandbox
      // You can save the sandbox ID in your database to resume the sandbox later
      await sbx.pause()

      // Remove the sandbox
      await sbx.kill()

      // Remove sandbox by id
      await Sandbox.kill(sbx.sandboxId)
      ```
    </CodeBlockTab>

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

      sbx = Sandbox.create()

      # Pause the sandbox
      sbx.pause()

      # Remove the sandbox
      sbx.kill()

      # Remove sandbox by id
      Sandbox.kill(sbx.sandbox_id)
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Sandbox's timeout [#sandboxs-timeout]

When you connect to a sandbox, the timeout resets. The default is 5 minutes, but you can pass a custom timeout to the `Sandbox.connect()` method:

<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.connect(sandboxId, { timeoutMs: 60 * 1000 }) // 60 seconds
      ```
    </CodeBlockTab>

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

      sbx = Sandbox.connect(sandbox_id, timeout=60) # 60 seconds
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

### Auto-pause [#auto-pause]

Auto-pause is configured in the sandbox lifecycle on create. `onTimeout`/`on_timeout` defaults to `"kill"`, meaning the sandbox is terminated when its timeout expires. Set it to `"pause"` to auto-pause on timeout instead.

<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 sandbox = await Sandbox.create({
        timeoutMs: 10 * 60 * 1000, // Optional: change default timeout (10 minutes)
        lifecycle: {
          onTimeout: 'pause', // Defaults to 'kill'; set to 'pause' to auto-pause on timeout
          autoResume: false, // Optional (default is false)
        },
      })
      ```
    </CodeBlockTab>

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

      sandbox = Sandbox.create(
          timeout=10 * 60,  # Optional: change default timeout (10 minutes)
          lifecycle={
              "on_timeout": "pause",  # Defaults to "kill"; set to "pause" to auto-pause on timeout
              "auto_resume": False,   # Optional (default is False)
          },
      )
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

Auto-pause is persistent, meaning if your sandbox resumes and later times out again, it will pause again.

To make the auto-pause filesystem-only — dropping memory so resume cold-boots — use the object form `onTimeout: { action: 'pause', keepMemory: false }` (JavaScript) / `"on_timeout": {"action": "pause", "keep_memory": False}` (Python). See [Filesystem-only snapshots](/docs/sandbox/filesystem-only-snapshots).

If you call `.kill()`, the sandbox is permanently deleted and cannot be resumed.

For auto-resume behavior, see [AutoResume](/docs/sandbox/auto-resume).

## Network [#network]

If you have a service (for example a server) running inside your sandbox and you pause the sandbox, the service won't be accessible from the outside and all the clients will be disconnected.
If you resume the sandbox, the service will be accessible again but you need to connect clients again.

## Limitations [#limitations]

### Pause and resume performance [#pause-and-resume-performance]

* Pausing a sandbox takes approximately **4 seconds per 1 GiB of RAM**
* Resuming a sandbox takes approximately **1 second**

### Paused sandbox retention [#paused-sandbox-retention]

* Paused sandboxes are kept **indefinitely**; there is no automatic deletion or time-to-live limit
* There is currently **no configurable "auto-kill after N days" option**; a paused sandbox will not expire on its own
* You can resume a paused sandbox at any time
* To remove a paused sandbox, you must kill it explicitly with an API call (`sandbox.kill()` / `Sandbox.kill(sandboxId)`), as shown in [Removing paused sandboxes](#removing-paused-sandboxes)

### Continuous runtime limits [#continuous-runtime-limits]

* A sandbox can remain running (without being paused) for:
  * **24 hours** on the **Pro tier**
  * **1 hour** on the **Hobby tier**
* After a sandbox is paused and resumed, the continuous runtime limit is **reset**
