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