e2b-template

star 2

Build custom E2B sandbox templates with pre-installed packages, servers, and configurations. Use when you need to create reusable sandbox environments with specific tools, dependencies, or startup commands.

beran-t By beran-t schedule Updated 2/17/2026

name: e2b-template description: > Build custom E2B sandbox templates with pre-installed packages, servers, and configurations. Use when you need to create reusable sandbox environments with specific tools, dependencies, or startup commands.

E2B Templates — Build Custom Sandbox Environments

Templates define custom sandbox environments with pre-installed packages, files, and startup commands. Build once, create sandboxes from them instantly.

When to Use Templates

  • Pre-install packages (Python, Node.js, system) to avoid install time on each sandbox
  • Set up servers or services that start automatically
  • Include project files, configs, or datasets
  • Create consistent environments across multiple sandboxes

Template Builder API

Templates use a fluent builder pattern — chain methods, then call Template.build().

import { Template, waitForPort } from 'e2b'

const template = Template()
  .fromPythonImage('3.13')
  .pipInstall(['fastapi', 'uvicorn'])
  .copy('./app', '/home/user/app')
  .setWorkdir('/home/user/app')
  .setStartCmd('uvicorn main:app --host 0.0.0.0 --port 8000', waitForPort(8000))

await Template.build(template, 'my-fastapi-app')
from e2b import Template, wait_for_port

template = (
    Template()
    .from_python_image("3.13")
    .pip_install(["fastapi", "uvicorn"])
    .copy("./app", "/home/user/app")
    .set_workdir("/home/user/app")
    .set_start_cmd("uvicorn main:app --host 0.0.0.0 --port 8000", wait_for_port(8000))
)

Template.build(template, "my-fastapi-app")

Base Images

Start from a pre-built image:

Method (JS) Method (Python) Description
Template().fromBaseImage() Template().from_base_image() Default Ubuntu base
Template().fromPythonImage('3.13') Template().from_python_image('3.13') Python with pip
Template().fromNodeImage('22') Template().from_node_image('22') Node.js with npm
Template().fromUbuntuImage('22.04') Template().from_ubuntu_image('22.04') Specific Ubuntu version
Template().fromBunImage('1.0') Template().from_bun_image('1.0') Bun runtime
Template().fromImage('image:tag') Template().from_image('image:tag') Any OCI image
Template().fromTemplate('name') Template().from_template('name') Extend existing template
Template().fromDockerfile('.') Template().from_dockerfile('.') Build from Dockerfile

Package Installation

template.pipInstall(['numpy', 'pandas'])          // pip install
template.pipInstall(['tensorflow'], { g: false })  // Not global
template.npmInstall(['express', 'cors'])            // npm install
template.npmInstall(['typescript'], { g: true })    // Global install
template.bunInstall(['elysia'])                     // bun install
template.aptInstall(['curl', 'git', 'vim'])         // apt-get install
template.pip_install(["numpy", "pandas"])
template.pip_install(["tensorflow"], g=False)
template.npm_install(["express", "cors"])
template.npm_install(["typescript"], g=True)
template.bun_install(["elysia"])
template.apt_install(["curl", "git", "vim"])

File Operations

template.copy('./local/file', '/sandbox/path')
template.copyItems([
  { src: './config.json', dest: '/home/user/config.json' },
  { src: './scripts/', dest: '/home/user/scripts/' },
])
template.makeDir('/home/user/data', { mode: 0o755 })
template.remove('/tmp/old', { recursive: true, force: true })
template.rename('/old/path', '/new/path', { force: true })
template.makeSymlink('/usr/bin/python3', '/usr/bin/python')
template.copy("./local/file", "/sandbox/path")
template.copy_items([
    {"src": "./config.json", "dest": "/home/user/config.json"},
    {"src": "./scripts/", "dest": "/home/user/scripts/"},
])
template.make_dir("/home/user/data", mode=0o755)
template.remove("/tmp/old", recursive=True, force=True)
template.rename("/old/path", "/new/path", force=True)
template.make_symlink("/usr/bin/python3", "/usr/bin/python")

Running Commands During Build

template.runCmd('echo "Build step"')
template.runCmd(['cmd1', 'cmd2'])              // Multiple sequential commands
template.runCmd('whoami', { user: 'root' })    // Run as specific user
template.gitClone('https://github.com/org/repo.git', '/home/user/repo', {
  branch: 'main', depth: 1,
})
template.run_cmd("echo 'Build step'")
template.run_cmd(["cmd1", "cmd2"])
template.run_cmd("whoami", user="root")
template.git_clone("https://github.com/org/repo.git", "/home/user/repo",
    branch="main", depth=1)

Configuration

template.setWorkdir('/home/user/app')
template.setUser('appuser')
template.setEnvs({ DATABASE_URL: 'postgres://...', NODE_ENV: 'production' })
template.set_workdir("/home/user/app")
template.set_user("appuser")
template.set_envs({"DATABASE_URL": "postgres://...", "NODE_ENV": "production"})

Important: setEnvs()/set_envs() sets build-time environment variables only. For runtime envs, use Sandbox.create({ envs: { ... } }).

Start & Ready Commands

The start command runs automatically when a sandbox is created from the template. The ready command (or helper) tells E2B when the sandbox is ready for use.

import { waitForPort, waitForProcess, waitForFile, waitForTimeout } from 'e2b'

// Start a server, wait for it to be ready
template.setStartCmd('npm start', waitForPort(3000))

// Other ready helpers
template.setStartCmd('python server.py', waitForProcess('gunicorn'))
template.setStartCmd('./init.sh', waitForFile('/tmp/ready'))
template.setStartCmd('./init.sh', waitForTimeout(5000))  // wait 5 seconds

// Custom ready command string
template.setStartCmd('npm start', 'curl -s http://localhost:3000/health')

// Set ready command separately
template.setReadyCmd(waitForPort(8080))
from e2b import wait_for_port, wait_for_process, wait_for_file, wait_for_timeout

template.set_start_cmd("npm start", wait_for_port(3000))
template.set_start_cmd("python server.py", wait_for_process("gunicorn"))
template.set_start_cmd("./init.sh", wait_for_file("/tmp/ready"))
template.set_start_cmd("./init.sh", wait_for_timeout(5000))

template.set_start_cmd("npm start", "curl -s http://localhost:3000/health")

template.set_ready_cmd(wait_for_port(8080))

Building Templates

Standard build (blocks until complete)

import { Template, defaultBuildLogger } from 'e2b'

await Template.build(template, 'my-app', {
  cpuCount: 2,
  memoryMB: 2048,
  skipCache: false,
  onBuildLogs: defaultBuildLogger(),
})
from e2b import Template, default_build_logger

Template.build(
    template,
    "my-app",
    cpu_count=2,
    memory_mb=2048,
    skip_cache=False,
    on_build_logs=default_build_logger(),
)

Background build (non-blocking)

const buildInfo = await Template.buildInBackground(template, 'my-app', {
  cpuCount: 2,
  memoryMB: 2048,
})

// Poll for status
const status = await Template.getBuildStatus(buildInfo, { logsOffset: 0 })
console.log(status.status) // 'building' | 'ready' | 'error'
build_info = Template.build_in_background(template, "my-app", cpu_count=2, memory_mb=2048)

status = Template.get_build_status(build_info, logs_offset=0)
print(status.status)  # 'building' | 'ready' | 'error'

Tags & Versioning

Templates support tags for version management using the name:tag format.

Default tag

When no tag is specified, default is used automatically:

  • my-template = my-template:default

Build with tags

// Single tag
await Template.build(template, 'my-app:v1.0.0')

// Multiple tags for the same build artifact
await Template.build(template, 'my-app', { tags: ['v1.2.0', 'latest'] })
Template.build(template, "my-app:v1.0.0")
Template.build(template, "my-app", tags=["v1.2.0", "latest"])

Manage tags (without rebuilding)

// Promote a version to production
await Template.assignTags('my-app:v1.2.0', 'production')
await Template.assignTags('my-app:v1.2.0', ['production', 'stable'])

// Remove a tag
await Template.removeTags('my-app', 'staging')
Template.assign_tags("my-app:v1.2.0", "production")
Template.assign_tags("my-app:v1.2.0", tags=["production", "stable"])
Template.remove_tags("my-app", "staging")

Use tagged templates

const sandbox = await Sandbox.create('my-app:production')
sandbox = Sandbox.create("my-app:production")

Template Naming

Names are team-scoped:

  • Within your team: my-app
  • Full reference: your-team-slug/my-app
  • Public templates: use team-slug/template-name

Check if a name is available

const exists = await Template.exists('my-template')
exists = Template.exists("my-template")

Complete Example: Python Data Science Template

import { Template, defaultBuildLogger } from 'e2b'

const template = Template()
  .fromPythonImage('3.13')
  .pipInstall(['numpy', 'pandas', 'matplotlib', 'scikit-learn', 'jupyter'])
  .aptInstall(['graphviz'])
  .copy('./notebooks', '/home/user/notebooks')
  .setWorkdir('/home/user/notebooks')
  .setEnvs({ MPLBACKEND: 'Agg' })

await Template.build(template, 'data-science', {
  cpuCount: 2,
  memoryMB: 4096,
  tags: ['v1.0.0', 'latest'],
  onBuildLogs: defaultBuildLogger(),
})
from e2b import Template, default_build_logger

template = (
    Template()
    .from_python_image("3.13")
    .pip_install(["numpy", "pandas", "matplotlib", "scikit-learn", "jupyter"])
    .apt_install(["graphviz"])
    .copy("./notebooks", "/home/user/notebooks")
    .set_workdir("/home/user/notebooks")
    .set_envs({"MPLBACKEND": "Agg"})
)

Template.build(
    template,
    "data-science",
    cpu_count=2,
    memory_mb=4096,
    tags=["v1.0.0", "latest"],
    on_build_logs=default_build_logger(),
)
Install via CLI
npx skills add https://github.com/beran-t/e2b-claude-skills --skill e2b-template
Repository Details
star Stars 2
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator