The short version: E2B's Build System 2.0 removes the two things that made custom sandbox templates annoying — the separate e2b.Dockerfile and the manual e2b template build CLI step. You now define the environment in the same Python or TypeScript SDK you use to launch sandboxes, and the build runs itself when your script executes. Here's the whole pattern, plus the one thing this design does that a Dockerfile fundamentally can't.

Why bother building a template at all#

If your agent runs code in a fresh E2B sandbox, the base image is minimal. The first thing most agents do is pip install or npm install a pile of dependencies — every single time a box boots. That's dead time on the critical path, paid on every cold start.

A template bakes those dependencies into the image once. Boot a sandbox from it and the packages are already there. The old way to do this was to write an e2b.Dockerfile, keep an e2b.toml beside it, and run a CLI build whenever it changed — a second toolchain living outside your app. Build System 2.0 folds all of that back into code.

The new way: a template is a value#

You describe the environment as a chain of build steps. TypeScript:

import { Template, waitForPort } from "e2b"

const template = Template()
  .fromImage("node:24")
  .copy("src/", ".")
  .runCmd("npm install")
  .setStartCmd("npm start", waitForPort(3000))

await Template.build(template, {
  alias: "my-agent-env",
  cpuCount: 2,
  memoryMB: 1024,
})

Python is the same shape:

from e2b import Template, wait_for_port

template = (
    Template()
    .from_image("python:3.11")
    .pip_install(["requests", "numpy"])
    .copy("app.py", ".")
    .set_start_cmd("python app.py", wait_for_port(8000))
)

Template.build(template, alias="my-agent-env", cpu_count=2, memory_mb=1024)

Three things changed from the Dockerfile era. There's no separate file — the template lives in your app, so it gets type hints and linting. There's no CLI step — Template.build() runs the build for you. And setStartCmd takes a readiness check: waitForPort(3000) blocks the build until the port is live, so a sandbox launched from this template comes up with the service already running, not "starting." (See the start-command docs for the other ready-check helpers.)

Launching from the template#

Once it's built and registered under an alias, launching is unchanged — you pass the alias where you used to pass a template name:

from e2b_code_interpreter import Sandbox

sbx = Sandbox.create(template="my-agent-env", timeout=300)
sbx.run_code("import numpy as np; print(np.__version__)")

Everything you baked in is present at boot. Pair this with pause/resume and the box keeps its state across turns and skips dependency install on the first one.

The part a Dockerfile can't do#

Here is the non-obvious win. Because the template is now ordinary code, you can build it dynamically, at runtime, from inside your app. A Dockerfile is a static artifact: you decide its contents at author time, and every user gets the same image. A Build System 2.0 template is a value your program computes — which means an agent can decide what its own environment should contain.

Concretely: a coding agent reads a task, infers it needs pandas, duckdb, and matplotlib, and assembles exactly that template on the spot — no pre-baked "kitchen-sink" image carrying fifty libraries the task will never touch.

def env_for(task_packages: list[str]):
    return (
        Template()
        .from_image("python:3.11")
        .pip_install(task_packages)
    )

template = env_for(agent_planned_packages)   # computed from the task
Template.build(template, alias=f"task-{task_id}")

The environment stops being a fixed image you maintain and becomes a function of the work. That's the shift Build System 2.0 is really about; the missing Dockerfile is just the visible half.

When the Dockerfile still wins#

Not every case. If you already maintain a heavy, multi-stage Docker image — system libraries, compiled extensions, a base your whole company shares — E2B still builds from Dockerfiles, and there's no reason to rewrite it. Build System 2.0 is the better default for agent workloads: small, specific, sometimes computed on the fly. Start in code; reach for a Dockerfile only when the image genuinely outgrows it.

If you're still choosing a sandbox provider at all, the E2B vs Modal vs Daytona breakdown covers that decision first.