Migrate from E2B
The Impello SDKs are a copy of E2B's clients, so most of your code does not change. Swap the package, swap the key, rebuild your templates.
Install the new packages
@impello/sdk replaces e2b on npm and impello replaces e2b on PyPI.
Neither package depends on the one it replaces.
npm uninstall e2b
npm install @impello/sdkThe TypeScript SDK needs Node 20.18.1 or later on the 20 line, or Node 22 or later. Node 21 is not supported. The Python SDK needs Python 3.10 or later.
Only the import line changes in most files. The class, the modules and the method names are the same.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
const result = await sandbox.commands.run('uname -a')
console.log(result.stdout)
await sandbox.kill()Change the key
An Impello key is imp_ followed by hexadecimal characters. Make one at
dashboard.impello.ai/keys; see
API keys.
A key minted under the older e2b_ prefix cannot be made to work by any
client. The API compares the whole prefix before it hashes anything, so no
client-side flag or option makes one pass. Create a new key and replace the
old value everywhere it is used.
The two SDKs fail differently on an old key. The Python SDK recognises the
e2b_ prefix and raises AuthenticationException before a request leaves the
process. The TypeScript SDK accepts both shapes on the client side and lets
the API answer, so you get HTTP 401 raised as AuthenticationError. See
Errors.
Check a new key against the API before you change anything else.
export IMPELLO_API_KEY=imp_...
curl "https://api.sandbox.impello.ai/v2/sandboxes" \
-H "X-API-Key: $IMPELLO_API_KEY"
A 200 with a JSON list means the key is good. A 401 means it is not.
Environment variables
Every connection setting is read under its IMPELLO_ name first and the
matching E2B_ name second. An environment that already exports the older
names keeps working, so you can rename on your own schedule.
| Impello name | Also read as | Default | What it does |
|---|---|---|---|
IMPELLO_API_KEY | E2B_API_KEY | none | The key. Starts with imp_ |
IMPELLO_DOMAIN | E2B_DOMAIN | sandbox.impello.ai | The domain the API and the sandboxes sit on |
IMPELLO_API_URL | E2B_API_URL | https://api. plus the domain | The API address |
IMPELLO_VALIDATE_API_KEY | E2B_VALIDATE_API_KEY | true | Set to false to skip the key shape check. TypeScript only |
IMPELLO_DEBUG | E2B_DEBUG | false | Talk to http://localhost:3000 instead of the API, and address sandboxes at localhost:<port> |
IMPELLO_SANDBOX_URL | E2B_SANDBOX_URL | none | Forces every sandbox connection to one fixed host; leave it unset |
Two smaller groups follow different rules.
- The TypeScript connection-pool variables have no
IMPELLO_name at all:E2B_API_CONNECTIONS,E2B_API_INFLIGHT_REQUESTS,E2B_ENVD_RPC_CONNECTIONS,E2B_ENVD_INFLIGHT_REQUESTSandE2B_ENVD_RPC_INFLIGHT_REQUESTS. Keep the old names; renaming them silently restores the defaults. - The Python pool settings take both prefixes:
IMPELLO_CONNECTION_RETRIES(3),IMPELLO_KEEPALIVE_EXPIRY(300seconds) andIMPELLO_MAX_KEEPALIVE_CONNECTIONS(20).
IMPELLO_ACCESS_TOKEN is read by the TypeScript SDK only, and it is
deprecated. Send the token as an Authorization header through apiHeaders
instead. The Python SDK never reads it.
Rebuild your templates
Templates do not transfer. There is no import, and nothing copies an image between fleets, so every custom template has to be built again here. Snapshots and paused sandboxes do not transfer either: a paused sandbox exists only on the fleet that paused it.
The default template names carry over. base, code-interpreter, claude,
codex, opencode, pi, amp, droid, grok, openclaw, k3s,
desktop and omarchy all exist here under those names. A
Sandbox.create() call that names one of them needs no edit. claude also
answers to claude-code, and code-interpreter to code-interpreter-v1.
desktop is the one to check: it exists under the same name, but it declares
no start command, so the graphical stack is not running when the sandbox
boots. See Templates.
For a custom template, rewrite the definition against the builder at
@impello/sdk/template and build it once. The builder reads your key from
IMPELLO_API_KEY (or E2B_API_KEY), or from an apiKey passed in the build
options.
import { Template } from '@impello/sdk/template'
const template = Template()
.fromTemplate('base')
.aptInstall(['ffmpeg'])
await Template.build(template, 'my-app:v1')
The builder is a subpath rather than a root export, so code that only creates sandboxes never loads a Dockerfile parser. Full reference: Build a custom template.
What is the same
Both packages are E2B's clients vendored under the MIT licence, with the API
address, the key check and the differences listed below changed. The
TypeScript SDK tracks E2B's client at 2.32.0; @impello/sdk carries its own
version number. That means:
- The same class and the same modules:
Sandbox,sandbox.files,sandbox.commands,sandbox.pty,sandbox.git. - The same methods, including
create,connect,list,kill,pause,setTimeout(set_timeout),getInfo(get_info) andgetMetrics(get_metrics). - The same error and exception class names, so existing
catchandexceptblocks still match. See Errors. - The same sandbox options:
template,timeoutMs(timeout),envs,metadataand the network options. - The same authentication header. HTTP callers send
X-API-Key, now againsthttps://api.sandbox.impello.ai.
What is different
- Package names.
@impello/sdkandimpello. - Key prefix.
imp_, and old keys cannot be reused. - Default domain.
sandbox.impello.ai, note2b.app. Leave the domain unset and the SDK resolves the right fleet on its own. - Sandbox hosts. Every sandbox is reached at
https://<port>-<sandboxId>.sandbox.impello.ai, routed by theHostheader. There is no single stablesandbox.<domain>host, andsandbox.impello.aiis deliberately left out of the SDK's list of domains that serve one, because adding it would buildhttps://sandbox.sandbox.impello.ai. UsegetHost(port)(get_host(port)in Python); see Network and public URLs. - The template builder is a subpath.
@impello/sdk/template, not the root import. - Static calls honour
apiUrl.Sandbox.list,kill,pauseandsetTimeouttakeSandboxApiOpts, which now includesapiUrl. Upstream left it off the type while reading it at runtime. Passing one option bag to bothcreateandlistused to drop the URL silently and send the call to the default host. - Python has three things TypeScript does not.
Impellobinds connection options instead of reading the environment.Sandbox.forkcheckpoints a running sandbox and starts copies from the snapshot.iamtypes workload identity onSandbox.create; it has no TypeScript counterpart and is not supported.
What Impello does not ship
These exist upstream and have no counterpart here. If your integration uses one, it has to be replaced before you move.
- A CLI. There is no
impellocommand in any language, and no package installs a binary. Everything is done through the SDKs, the HTTP API or the dashboard. - Volumes. No volume client in either SDK and no persistent volume to
mount. Both SDKs still type a
volumeMounts(volume_mounts) option onSandbox.create. There is nothing to mount; do not use it. Use the sandbox filesystem and snapshots instead. - Secrets. No secrets client in either SDK. Pass values with
envsonSandbox.createand keep them in your own secret store. - A code-interpreter client package. The
code-interpretertemplate exists and starts Jupyter with the sandbox, behind an HTTP server on port 49999, but neither SDK ships a client for it. Drive it withsandbox.commands, or reach that HTTP server withgetHost(49999)(get_host(49999)in Python); Jupyter itself listens onlocalhost:8888inside the sandbox. See Templates. - A desktop client. Neither SDK has screenshot, click or stream methods.
The
omarchytemplate serves a desktop over noVNC on port 6080, with no VNC password. The port is public unless you setnetwork: { allowPublicTraffic: false }(network={"allow_public_traffic": False}in Python). See Network and public URLs. You reach the desktop yourself. - An MCP gateway. The SDK types still carry MCP server names and an
mcpoption, but the gateway template they resolve to is not built here. Withmcpand no template,createboots a template namedmcp-gatewaythat was never built here, so the call fails. Do not use them. - Other names the types still carry.
lifecycle.autoResume(auto_resume),network.maskRequestHost(mask_request_host) andgetMcpUrl()andgetMcpToken()(get_mcp_url(),get_mcp_token()) are in the types but are not part of the supported surface. Leave them unset. - A template builder in Python. TypeScript only, as above.
Errors lists every class each SDK raises.