Skip to main content
Many workloads don’t need a sandbox running all the time, but when they do need it, it should just work, whether it was paused or not. AutoResume handles this automatically: a paused sandbox wakes up when activity arrives, so your code does not have to check or manage sandbox state. Configure it through the lifecycle object when creating a sandbox.

Configure lifecycle on create

import { Sandbox } from 'e2b'

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

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().

Timeout after auto-resume

When a sandbox auto-resumes, it starts a new timeout equal to the original timeout set at creation. The countdown begins from the moment the sandbox resumes, not from when it was first created. For example, if you create a sandbox with a 10-minute timeout:
  1. The sandbox runs for 10 minutes, then pauses.
  2. Activity arrives and the sandbox auto-resumes.
  3. A fresh 10-minute timeout starts.
  4. If no further activity resets the timeout, the sandbox pauses again after 10 minutes.
This cycle repeats every time the sandbox auto-resumes — the lifecycle configuration (onTimeout: "pause" + autoResume: true) is persistent across pause/resume cycles.
You can change the timeout after the sandbox resumes by calling setTimeout/set_timeout. See Change sandbox timeout during runtime.

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
  • 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. Each time the sandbox resumes, the original timeout resets — so the sandbox keeps cycling between running and paused as long as activity arrives. If you call .kill(), the sandbox is permanently deleted and cannot be resumed.