Skip to main content
E2B sandboxes are persistent environments. When you pause a sandbox, its full state — filesystem and memory, including all running processes and loaded variables — is preserved indefinitely. Resume it at any time and pick up exactly where you left off. Snapshots let you capture that state and spawn multiple new sandboxes from it.

Sandbox state transitions

Understanding how sandboxes transition between states:

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.
  • Killed: The sandbox is terminated and all resources are released. This is a terminal state.

Changing sandbox state

import { Sandbox } from '@e2b/code-interpreter'

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

Pause and resume

Pausing a 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.
import { Sandbox } from '@e2b/code-interpreter'

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)

Resuming a 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.
import { Sandbox } from '@e2b/code-interpreter'

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)

Listing paused sandboxes

You can list all paused sandboxes by calling the Sandbox.list method and supplying the state query parameter.
import { Sandbox, SandboxInfo } from '@e2b/code-interpreter'

// 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)
}

Removing paused sandboxes

You can remove paused sandboxes by calling the kill method on the Sandbox instance.
import { Sandbox } from '@e2b/code-interpreter'

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)

Timeout on connect

When you connect to a sandbox, the inactivity timeout resets. The default is 5 minutes, but you can pass a custom timeout to the Sandbox.connect() method:
import { Sandbox } from '@e2b/code-interpreter'

const sbx = await Sandbox.connect(sandboxId, { timeoutMs: 60 * 1000 }) // 60 seconds

Network behavior during pause

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

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 sandboxes are kept indefinitely — there is no automatic deletion or time-to-live limit
  • You can resume a paused sandbox at any time

Continuous runtime limits

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

Auto-pause and auto-resume

Auto-pause and auto-resume are configured together through the lifecycle object when creating a sandbox. Auto-pause suspends a sandbox when its timeout expires. Auto-resume wakes it back up when activity arrives.

Configure lifecycle on create

import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create({
  timeoutMs: 10 * 60 * 1000,
  lifecycle: {
    onTimeout: 'pause',    // auto-pause when timeout expires
    autoResume: true,       // auto-resume when activity arrives
  },
})
Auto-pause is persistent — if your sandbox resumes and later times out again, it will pause again. If you call .kill(), the sandbox is permanently deleted and cannot be resumed.

Lifecycle options

  • onTimeout / on_timeout
    • kill (default): sandbox is terminated when timeout is reached
    • pause: sandbox is paused when timeout is reached
  • autoResume / auto_resume
    • false (default): paused sandboxes do not auto-resume
    • true: paused sandboxes auto-resume on activity
    • true is valid only when onTimeout/on_timeout is pause

Behavior summary

  • Default behavior is equivalent to onTimeout: "kill" with autoResume: false.
  • onTimeout: "pause" with autoResume: false gives auto-pause without auto-resume.
  • onTimeout: "pause" with autoResume: true gives auto-pause with auto-resume.
  • Sandbox.connect() can still be used to resume a paused sandbox manually.
If you use autoResume: false, resume explicitly with Sandbox.connect().

What counts as activity

Auto-resume is triggered by the sandbox activity - that’s both HTTP traffic and controlling the sandbox from the SDK. That includes SDK operations like:
  • sandbox.commands.run(...)
  • sandbox.files.read(...)
  • sandbox.files.write(...)
  • opening a tunneled app URL or sending requests to a service running inside the sandbox
If a sandbox is paused and autoResume is enabled, the next supported operation resumes it automatically. You do not need to call Sandbox.connect() first.

SDK example: pause, then read a file

import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create({
  timeoutMs: 10 * 60 * 1000,
  lifecycle: {
    onTimeout: 'pause',
    autoResume: true,
  },
})

await sandbox.files.write('/home/user/hello.txt', 'hello from a paused sandbox')
await sandbox.pause()

const content = await sandbox.files.read('/home/user/hello.txt')
console.log(content)
console.log(`State after read: ${(await sandbox.getInfo()).state}`)

Use cases

Web and dev/preview servers

Use onTimeout: "pause" + autoResume: true so inbound traffic can wake a paused sandbox automatically. This works for both basic web/API servers and dev or preview servers you open occasionally.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create({
  timeoutMs: 10 * 60 * 1000,
  lifecycle: {
    onTimeout: 'pause',
    autoResume: true,
  },
})

await sandbox.commands.run(
  `python3 -m pip -q install 'flask>=2.2'`
)

await sandbox.files.write(
  '/home/user/app.py',
  [
    'from flask import Flask',
    'app = Flask(__name__)',
    '@app.route("/")',
    'def hello():',
    '    return "Hello, World!"',
    'app.run(host="0.0.0.0", port=3000)',
    '',
  ].join('\n')
)

await sandbox.commands.run(
  'python3 -u /home/user/app.py > /home/user/flask.log 2>&1',
  { background: true }
)

await new Promise((resolve) => setTimeout(resolve, 1000))

const previewHost = sandbox.getHost(3000)
console.log(`Preview URL: https://${previewHost}`)

console.log(`Status before pause: ${(await sandbox.getInfo()).state}`)
await sandbox.pause()
console.log(`Status after pause: ${(await sandbox.getInfo()).state}`)

Agent/tool execution

For queued tasks or tool calls, create once and keep using the same sandbox handle. If it is paused, it will auto-resume when you run the next command.
import { Sandbox } from 'e2b'

// One-time setup
const sandbox = await Sandbox.create({
  timeoutMs: 5 * 60 * 1000,
  lifecycle: {
    onTimeout: 'pause',
    autoResume: true,
  },
})

// Later: called for each agent/tool task
async function runToolTask(command) {
  const result = await sandbox.commands.run(command)
  return result.stdout
}

console.log(await runToolTask('python -c "print(2 + 2)"'))

Per-user sandboxes

For multi-tenant apps, keep a map of sandbox IDs by user. On each request, connect to the user’s existing sandbox (which auto-resumes if paused) or create a new one.
import { Sandbox } from 'e2b'

const userSandboxes = new Map() // userId → Sandbox

async function getSandbox(userId) {
  let sandbox = userSandboxes.get(userId)

  if (!sandbox) {
    sandbox = await Sandbox.create({
      timeoutMs: 5 * 60 * 1000,
      lifecycle: {
        onTimeout: 'pause',
        autoResume: true,
      },
    })
    userSandboxes.set(userId, sandbox)
  }

  return sandbox
}

// On each user request (auto-resumes if paused)
const sandbox = await getSandbox('user-123')
const result = await sandbox.commands.run('echo "Hello from your sandbox"')
console.log(result.stdout)

Cleanup

Auto-resume is persistent, meaning if your sandbox resumes and later times out again, it will pause again. If you call .kill(), the sandbox is permanently deleted and cannot be resumed.

Snapshots

Snapshots let you create a persistent point-in-time capture of a running sandbox, including both its filesystem and memory state. You can then use a snapshot to spawn new sandboxes that start from the exact same state. The original sandbox continues running after the snapshot is created, and a single snapshot can be used to create many new sandboxes.

Prerequisites

Snapshots require templates with envd version v0.5.0 or above. If you are using a custom template created before envd v0.5.0, you need to rebuild it. You can check the template envd version using the e2b template list command or by viewing the templates list on the dashboard.

Snapshots vs. Pause/Resume

Pause/ResumeSnapshots
Effect on original sandboxPauses (stops) the sandboxSandbox briefly pauses, then continues running
RelationshipOne-to-one — resume restores the same sandboxOne-to-many — snapshot can spawn many new sandboxes
Use caseSuspend and resume a single sandboxCreate a reusable checkpoint

Snapshot flow

The sandbox is briefly paused during the snapshot process but automatically returns to running state. The sandbox ID stays the same after the snapshot completes.
During the snapshot, the sandbox is temporarily paused and resumed. This causes all active connections (e.g. WebSocket, PTY, command streams) to be dropped. Make sure your client handles reconnection properly.

Create a snapshot

You can create a snapshot from a running sandbox instance.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

// Create a snapshot from a running sandbox
const snapshot = await sandbox.createSnapshot()
console.log('Snapshot ID:', snapshot.snapshotId)
You can also create a snapshot by sandbox ID using the static method.
import { Sandbox } from 'e2b'

// Create a snapshot by sandbox ID
const snapshot = await Sandbox.createSnapshot(sandboxId)
console.log('Snapshot ID:', snapshot.snapshotId)

Create a sandbox from a snapshot

The snapshot ID can be used directly with Sandbox.create() to spawn a new sandbox from the snapshot. The new sandbox starts with the exact filesystem and memory state captured in the snapshot.
import { Sandbox } from 'e2b'

const snapshot = await sandbox.createSnapshot()

// Create a new sandbox from the snapshot
const newSandbox = await Sandbox.create(snapshot.snapshotId)

List snapshots

You can list all snapshots. The method returns a paginator for iterating through results.
import { Sandbox } from 'e2b'

const paginator = Sandbox.listSnapshots()

const snapshots = []
while (paginator.hasNext) {
  const items = await paginator.nextItems()
  snapshots.push(...items)
}

Filter by sandbox

You can filter snapshots created from a specific sandbox.
import { Sandbox } from 'e2b'

const paginator = Sandbox.listSnapshots({ sandboxId: 'your-sandbox-id' })
const snapshots = await paginator.nextItems()

Delete a snapshot

import { Sandbox } from 'e2b'

// Returns true if deleted, false if the snapshot was not found
const deleted = await Sandbox.deleteSnapshot(snapshot.snapshotId)

Snapshots vs. Templates

Both snapshots and templates create reusable starting points for sandboxes, but they solve different problems.
TemplatesSnapshots
Defined byDeclarative code (Template builder)Capturing a running sandbox
ReproducibilitySame definition produces the same sandbox every timeCaptures whatever state exists at that moment
Best forRepeatable base environmentsCheckpointing, rollback, forking runtime state
Use templates when every sandbox should start from an identical, known state — pre-installed tools, fixed configurations, consistent environments. Use snapshots when you need to capture or fork live runtime state that depends on what happened during execution.

Snapshot use cases

  • Checkpointing agent work — an AI agent has loaded data and produced partial results in memory. Snapshot it so you can resume or fork from that point later.
  • Rollback points — snapshot before a risky or expensive operation (running untrusted code, applying a migration, refactoring a web app). If it fails, rollback - spawn a fresh sandbox from the snapshot before the operation happened.
  • Forking workflows — spawn multiple sandboxes from the same snapshot to explore different approaches in parallel.
  • Cached sandboxes — avoid repeating expensive setup by snapshotting a sandbox that has already loaded a large dataset or started a long-running process.
  • Sharing state — one user or agent configures an environment interactively, snapshots it, and others start from that exact state.