| name | migrate-from-e2b |
| description | Use when migrating sandbox code from E2B (@e2b/code-interpreter or e2b) to Blaxel (@blaxel/core or blaxel). Covers API mapping for sandbox creation, command execution, filesystem operations, pause/resume, and authentication in both TypeScript and Python. Reach for this skill when you encounter E2B SDK imports or need to replace E2B sandbox calls with Blaxel equivalents. |
Migrate from E2B to Blaxel
This guide covers migrating cloud sandbox code from E2B (@e2b/code-interpreter / e2b) to Blaxel (@blaxel/core / blaxel).
Package replacement
| Language | E2B | Blaxel |
|---|
| TypeScript | @e2b/code-interpreter or e2b | @blaxel/core |
| Python | e2b-code-interpreter or e2b | blaxel |
npm uninstall @e2b/code-interpreter e2b
npm install @blaxel/core
pip uninstall e2b-code-interpreter e2b
pip install blaxel
Authentication
| E2B | Blaxel |
|---|
E2B_API_KEY env var | BL_WORKSPACE + BL_API_KEY env vars |
Single API key, passed via env or apiKey option | CLI login, .env, env vars, or config file (auto-detected) |
Blaxel authenticates automatically when logged in via CLI (bl login YOUR-WORKSPACE). No need to set API keys in code.
API mapping
Imports
TypeScript:
import { Sandbox } from '@e2b/code-interpreter'
import { SandboxInstance } from '@blaxel/core'
Python:
from e2b_code_interpreter import Sandbox
from blaxel.core import SandboxInstance
Sandbox creation
TypeScript:
const sandbox = await Sandbox.create()
const sandbox = await Sandbox.create({
timeoutMs: 300_000,
envs: { NODE_ENV: 'production' },
metadata: { project: 'my-app' },
})
const sandbox = await Sandbox.create('my-template-id', {
timeoutMs: 600_000,
})
const sandbox = await SandboxInstance.createIfNotExists({
name: 'my-sandbox',
image: 'blaxel/base-image:latest',
region: 'us-pdx-1',
memory: 2048,
ports: [{ target: 3000, protocol: 'HTTP' }],
envs: [
{ name: 'NODE_ENV', value: 'production' },
],
labels: { project: 'my-app' },
ttl: '24h',
})
Python:
sandbox = Sandbox()
sandbox = Sandbox(timeout=300, envs={"NODE_ENV": "production"}, metadata={"project": "my-app"})
sandbox = Sandbox("my-template-id", timeout=600)
sandbox = await SandboxInstance.create_if_not_exists({
"name": "my-sandbox",
"image": "blaxel/base-image:latest",
"region": "us-pdx-1",
"memory": 2048,
"ports": [{"target": 3000, "protocol": "HTTP"}],
"envs": [
{"name": "NODE_ENV", "value": "production"},
],
"labels": {"project": "my-app"},
"ttl": "24h",
})
Parameter mapping
| Parameter | E2B | Blaxel |
|---|
| Template / Image | Sandbox.create('template-id') | image: 'blaxel/base-image:latest' |
| Timeout | timeoutMs: 300000 (max 24h Pro / 1h Hobby) | ttl: '24h' (configurable per quota tier) |
| Environment vars | envs: { KEY: 'val' } (flat object, set at creation, inherited by commands) | envs: [{ name: 'KEY', value: 'val' }] (array of objects at creation) |
| Secrets | N/A | envs: [{ name: 'KEY', value: 'val', secret: true }] |
| Metadata / Labels | metadata: { k: 'v' } | labels: { k: 'v' } |
| Region | Not configurable | region: 'us-pdx-1' |
| Memory | Fixed per template | memory: 2048 (MB) |
| Ports | Implicit (all ports accessible via getHost) | ports: [{ target: 3000, protocol: 'HTTP' }] (declared at creation) |
| Name | Auto-generated ID | name: 'my-sandbox' (for idempotent creation) |
| Network / Internet | allowInternetAccess: false, network: { allow/deny rules } | network: { vpcName: 'my-vpc', egressGatewayName: 'my-gw' } (VPC + egress gateway). No fine-grained IP/domain rules |
| Secured access | secure: true, sandbox.trafficAccessToken | Private preview URLs with public: false + preview.tokens.create(expiresAt) |
| PTY / Terminal | sandbox.pty.create({ cols, rows, onData }) | N/A (no interactive terminal support) |
| GPU | Not available | N/A |
| Per-command user | user: 'root' on commands/pty | N/A (commands run as default user) |
| Metrics | sandbox.getMetrics() — CPU, memory, disk | N/A (no metrics API) |
Custom sandbox / templates
TypeScript:
const sandbox = await Sandbox.create('my-template-id')
const sandbox = await SandboxInstance.createIfNotExists({
name: 'my-sandbox',
image: 'my-custom-template-image',
region: 'us-pdx-1',
memory: 2048,
})
Python:
sandbox = Sandbox("my-template-id")
sandbox = await SandboxInstance.create_if_not_exists({
"name": "my-sandbox",
"image": "my-custom-template-image",
"region": "us-pdx-1",
"memory": 2048,
})
Template building methods mapping
E2B has programmatic template building via Template.build() with chainable methods. Blaxel uses standard Dockerfiles deployed with bl deploy. All E2B template methods map to Dockerfile instructions:
| E2B Template Method | Blaxel Dockerfile Equivalent |
|---|
fromBaseImage() | FROM e2b-default-image (use blaxel/base-image:latest) |
fromUbuntuImage(tag) | FROM ubuntu:tag |
fromDebianImage(tag) | FROM debian:tag |
fromPythonImage(tag) | FROM python:tag |
fromNodeImage(tag) | FROM node:tag |
fromBunImage(tag) | FROM oven/bun:tag |
fromImage(name) | FROM name |
fromDockerfile(content) | Use the Dockerfile directly as the Blaxel template |
fromTemplate(name) | Build on top of an existing deployed Blaxel template image |
runCmd(cmd) | RUN cmd |
aptInstall(['curl', 'git']) | RUN apt-get update && apt-get install -y curl git |
pipInstall(['numpy']) | RUN pip install numpy |
npmInstall(['express']) | RUN npm install -g express |
bunInstall(['hono']) | RUN bun install -g hono |
gitClone(url, path) | RUN git clone url path |
copy(src, dest) | COPY src dest |
remove(path) | RUN rm -rf path |
rename(old, new) | RUN mv old new |
makeDir(path) | RUN mkdir -p path |
makeSymlink(target, link) | RUN ln -s target link |
setWorkdir(path) | WORKDIR path |
setUser(user) | USER user |
setEnvs({KEY: 'val'}) | ENV KEY=val |
setStartCmd(cmd) | CMD cmd / configured via entrypoint.sh |
Template versioning: E2B supports Template.assignTags() and creation with Sandbox.create('template:v1.0.0'). Blaxel templates are deployed via bl deploy without version tagging.
Template pre-building: E2B's Template.build() and Template.buildInBackground() with Template.getBuildStatus(). Blaxel equivalent is bl deploy which builds and caches the image in Blaxel's private registry.
Command execution
TypeScript:
const result = await sandbox.commands.run('echo hello')
const result = await sandbox.commands.run('npm install', {
envs: { NODE_ENV: 'production' },
cwd: '/app',
})
const result = await sandbox.process.exec({
command: 'echo hello',
waitForCompletion: true,
})
const result = await sandbox.process.exec({
command: 'npm install',
workingDir: '/app',
env: { NODE_ENV: 'production' },
waitForCompletion: true,
})
Python:
result = sandbox.commands.run("echo hello")
result = sandbox.commands.run("npm install", envs={"NODE_ENV": "production"}, cwd="/app")
result = await sandbox.process.exec({
"command": "echo hello",
"wait_for_completion": True,
})
result = await sandbox.process.exec({
"command": "npm install",
"working_dir": "/app",
"env": {"NODE_ENV": "production"},
"wait_for_completion": True,
})
Background / streaming commands
TypeScript:
const command = await sandbox.commands.run('npm run dev', {
background: true,
cwd: '/app',
envs: { NODE_ENV: 'development' },
onStdout: (data) => console.log(data),
onStderr: (data) => console.error(data),
})
await sandbox.commands.kill(command.pid)
const devServer = await sandbox.process.exec({
name: 'dev-server',
command: 'npm run dev -- --host 0.0.0.0',
workingDir: '/app',
waitForPorts: [3000],
})
const proc = await sandbox.process.exec({
name: 'dev-server',
command: 'npm run dev -- --host 0.0.0.0',
workingDir: '/app',
waitForCompletion: false,
onLog: (log) => console.log(log),
})
await sandbox.process.kill('dev-server')
Python:
command = sandbox.commands.run("npm run dev", background=True, cwd="/app",
envs={"NODE_ENV": "development"},
on_stdout=lambda data: print(data),
on_stderr=lambda data: print(data),
)
sandbox.commands.kill(command.pid)
dev_server = await sandbox.process.exec({
"name": "dev-server",
"command": "npm run dev -- --host 0.0.0.0",
"working_dir": "/app",
"wait_for_ports": [3000],
})
await sandbox.process.kill("dev-server")
Log streaming / Process output
E2B streams output via onStdout/onStderr callbacks and returns results with stdout, stderr, exitCode. Blaxel offers similar callbacks plus additional methods for log retrieval and streaming.
TypeScript:
const result = await sandbox.commands.run('npm run build', {
cwd: '/app',
onStdout: (data) => console.log(data),
onStderr: (data) => console.error(data),
})
console.log(result.stdout, result.stderr, result.exitCode)
const result = await sandbox.process.exec({
command: 'npm run build',
workingDir: '/app',
onLog: (log) => console.log(log),
onStdout: (out) => process.stdout.write(out),
onStderr: (err) => process.stderr.write(err),
waitForCompletion: true,
})
const handle = sandbox.process.streamLogs('dev-server', {
onLog: (log) => console.log(log),
onStdout: (out) => process.stdout.write(out),
onStderr: (err) => process.stderr.write(err),
onError: (err) => console.error(err),
})
await handle.wait()
const logs = await sandbox.process.logs('dev-server')
const stdout = await sandbox.process.logs('dev-server', 'stdout')
const stderr = await sandbox.process.logs('dev-server', 'stderr')
Python:
result = sandbox.commands.run("npm run build", cwd="/app",
on_stdout=lambda data: print(data),
on_stderr=lambda data: print(data, file=sys.stderr),
)
print(result.stdout, result.stderr, result.exit_code)
cmd = sandbox.commands.run("long-task", background=True)
cmd.wait()
result = await sandbox.process.exec({
"command": "npm run build",
"working_dir": "/app",
"on_log": lambda log: print(log),
"wait_for_completion": True,
})
result = await sandbox.process.wait("dev-server", {
"max_wait": 300000,
"interval": 2000,
})
Sandbox lifecycle management
| Operation | E2B | Blaxel |
|---|
| Kill | sandbox.kill() or Sandbox.kill(sandboxId) | sandbox.delete() or SandboxInstance.delete('name') |
| Get info | sandbox.getInfo() → sandboxId, templateId, metadata, startedAt, endAt | SandboxInstance.get('name') → sandbox.metadata, sandbox.status, sandbox.spec, sandbox.lastUsedAt, sandbox.expiresIn |
| List sandboxes | Sandbox.list({ query: { state, metadata }, limit, nextToken }) — paginated, filterable | SandboxInstance.list() — returns all sandboxes. Labels in metadata for client-side filtering |
| Update timeout | sandbox.setTimeout(timeoutMs) / sandbox.set_timeout(timeout) — resets countdown from "now" | SandboxInstance.updateTtl('name', '48h') — updates TTL. Also SandboxInstance.updateLifecycle() for expiration policies |
| Exit code | result.exitCode / result.exit_code | result.exitCode on process response, or (await sandbox.process.get('name')).exitCode |
| Process wait | command.wait() (Python background) | sandbox.process.wait('name', { maxWait, interval }) |
| Process stop | sandbox.commands.kill(pid) (by PID) | sandbox.process.stop('name') (SIGTERM) or sandbox.process.kill('name') (SIGKILL) — by name |
| Process list | N/A | sandbox.process.list() |
| Process get | N/A | sandbox.process.get('name') — status, exitCode, pid, logs |
| Update labels | Via metadata at creation only | SandboxInstance.updateMetadata('name', { labels: {...} }) |
Filesystem operations
| Operation | E2B | Blaxel |
|---|
| Write file | sandbox.files.write(path, content) | sandbox.fs.write(path, content) |
| Read file | sandbox.files.read(path) | sandbox.fs.read(path) |
| List files | sandbox.files.list(path) | sandbox.fs.ls(path) |
| Create dir | sandbox.files.makeDir(path) / make_dir(path) | sandbox.fs.mkdir(path) |
| Delete file | sandbox.commands.run('rm path') | sandbox.fs.rm(path) / sandbox.fs.rm(path, { recursive: true }) |
| Copy file | sandbox.commands.run('cp ...') | sandbox.fs.cp(src, dest) |
| File info | sandbox.files.getInfo(path) → size, mode, permissions, owner, modifiedTime | N/A (fs.ls() returns names only, no detailed metadata) |
| Watch files | sandbox.files.watchDir(path, cb, { recursive? }) | sandbox.fs.watch(path, callback, { withContent: true, ignore: ['node_modules'] }) |
| Write tree | sandbox.files.write(files[]) (batch) | sandbox.fs.writeTree(files, basePath) / write_tree(files, base) |
| Write binary | sandbox.files.write(path, buffer) | sandbox.fs.writeBinary(path, buffer) / write_binary(path, bytes) |
| Read binary | sandbox.files.read(path, { format: 'bytes' }) | sandbox.fs.readBinary(path) / read_binary(path) |
| Upload URL | sandbox.uploadUrl(filename) — pre-signed URL | N/A (use sandbox.fs.write() / writeBinary() via SDK. Auto multipart for >5MB) |
| Download URL | sandbox.downloadUrl(path) — pre-signed URL | N/A (use sandbox.fs.read() / readBinary() via SDK) |
| Fuzzy search | N/A | sandbox.fs.search(query, path) |
| Search content | N/A | sandbox.fs.grep(pattern, path) |
| Find files | N/A | sandbox.fs.find(path, { patterns: ['*.ts'] }) |
TypeScript:
await sandbox.files.write('/app/file.txt', 'hello')
const content = await sandbox.files.read('/app/file.txt')
const files = await sandbox.files.list('/app')
await sandbox.fs.write('/app/file.txt', 'hello')
const content = await sandbox.fs.read('/app/file.txt')
const { subdirectories, files } = await sandbox.fs.ls('/app')
await sandbox.fs.writeTree([
{ path: 'src/index.ts', content: 'console.log("hello")' },
{ path: 'package.json', content: '{"name":"app"}' },
], '/app')
await sandbox.fs.rm('/app/temp.txt')
await sandbox.fs.rm('/app/old-dir', { recursive: true })
await sandbox.fs.cp('/app/file.txt', '/backup/file.txt')
const handle = sandbox.fs.watch('/app/src', (event) => {
console.log(event.op, event.path)
}, { withContent: true, ignore: ['node_modules', '.git'] })
Python:
sandbox.files.write("/app/file.txt", "hello")
content = sandbox.files.read("/app/file.txt")
files = sandbox.files.list("/app")
await sandbox.fs.write("/app/file.txt", "hello")
content = await sandbox.fs.read("/app/file.txt")
listing = await sandbox.fs.ls("/app")
await sandbox.fs.write_tree([
{"path": "src/index.ts", "content": 'console.log("hello")'},
{"path": "package.json", "content": '{"name":"app"}'},
], "/app")
await sandbox.fs.rm("/app/temp.txt")
await sandbox.fs.rm("/app/old-dir", recursive=True)
await sandbox.fs.cp("/app/file.txt", "/backup/file.txt")
def on_change(event):
print(event.op, event.path)
handle = sandbox.fs.watch("/app/src", on_change, {
"with_content": True,
"ignore": ["node_modules", ".git"]
})
Preview URLs
E2B provides getHost() / get_host() for accessing sandbox ports. Blaxel has dedicated preview URL management with access control.
TypeScript:
const host = sandbox.getHost(3000)
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: 'app-preview' },
spec: { port: 3000, public: true },
})
const url = preview.spec?.url
Python:
host = sandbox.get_host(3000)
preview = await sandbox.previews.create_if_not_exists({
"metadata": {"name": "app-preview"},
"spec": {"port": 3000, "public": True},
})
url = preview.spec.url
Secured / Private access
E2B uses secure: true with sandbox.trafficAccessToken for restricted access. Blaxel uses private preview URLs with token-based authentication.
TypeScript:
const sandbox = await Sandbox.create({ secure: true })
const host = sandbox.getHost(3000)
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: 'app-preview' },
spec: { port: 3000, public: false },
})
const token = await preview.tokens.create(new Date(Date.now() + 3600000))
const session = await sandbox.sessions.create({
expiresAt: new Date(Date.now() + 3600000),
})
Pause / Resume
E2B has explicit pause() / resume() methods (beta). Blaxel auto-scales to zero and resumes transparently.
TypeScript:
const sandboxId = sandbox.sandboxId
await sandbox.pause()
const sandbox = await Sandbox.connect(sandboxId)
const sandbox = await SandboxInstance.get('my-sandbox')
Python:
sandbox_id = sandbox.sandbox_id
sandbox.pause()
sandbox = Sandbox.connect(sandbox_id)
sandbox = await SandboxInstance.get("my-sandbox")
Snapshots
E2B supports explicit snapshots for saving and restoring sandbox state. Blaxel auto-preserves state through scale-to-zero.
TypeScript:
const snapshot = await sandbox.createSnapshot()
const snapshotId = snapshot.snapshotId
await sandbox.kill()
const restored = await Sandbox.create(snapshotId)
const snapshots = await Sandbox.listSnapshots()
await Sandbox.deleteSnapshot(snapshotId)
const sandbox = await SandboxInstance.get('my-sandbox')
Sandbox info & cleanup
TypeScript:
const info = await sandbox.getInfo()
await sandbox.kill()
const sandbox = await SandboxInstance.get('my-sandbox')
await sandbox.delete()
Python:
info = sandbox.get_info()
sandbox.kill()
sandbox = await SandboxInstance.get("my-sandbox")
await sandbox.delete()
Reconnect to existing sandbox
TypeScript:
const sandbox = await Sandbox.connect(sandboxId)
const sandbox = await SandboxInstance.get('my-sandbox')
Python:
sandbox = Sandbox.connect(sandbox_id)
sandbox = await SandboxInstance.get("my-sandbox")
Code Interpreter
E2B's @e2b/code-interpreter package provides runCode() for executing code in isolated interpreters with result/chart detection. Blaxel has a CodeInterpreter class with similar capabilities.
TypeScript:
import { Sandbox } from '@e2b/code-interpreter'
const sandbox = await Sandbox.create()
const execution = await sandbox.runCode('print("hello")', {
language: 'python',
onStdout: (data) => console.log(data),
onStderr: (data) => console.error(data),
})
console.log(execution.results, execution.logs, execution.error)
const context = await sandbox.createCodeContext({ language: 'python', cwd: '/app' })
await sandbox.runCode('x = 42', { context })
await sandbox.runCode('print(x)', { context })
import { CodeInterpreter } from '@blaxel/core'
const interpreter = await CodeInterpreter.createIfNotExists({
name: 'my-interpreter',
})
const result = await interpreter.runCode({
code: 'print("hello")',
language: 'python',
onStdout: (out) => console.log(out),
onStderr: (err) => console.error(err),
})
const context = await interpreter.createCodeContext({ language: 'python', name: 'my-ctx' })
await interpreter.runCode({ code: 'x = 42', context: 'my-ctx' })
await interpreter.runCode({ code: 'print(x)', context: 'my-ctx' })
Python:
from e2b_code_interpreter import Sandbox
sandbox = Sandbox()
execution = sandbox.run_code("print('hello')", language="python")
print(execution.results, execution.logs, execution.error)
from blaxel.core import CodeInterpreter
interpreter = await CodeInterpreter.create_if_not_exists({
"name": "my-interpreter",
})
result = await interpreter.run_code({
"code": "print('hello')",
"language": "python",
})
Note: E2B automatically detects Matplotlib charts and returns them as base64 PNG or structured chart objects. Blaxel's CodeInterpreter does not have automatic chart detection — chart output is captured as standard output from the Jupyter kernel.
Git integration
E2B provides a full sandbox.git.* API for git operations. Blaxel has no dedicated git API — use process.exec() with git commands instead.
TypeScript:
await sandbox.git.clone('https://github.com/user/repo.git', { path: '/app', depth: 1 })
await sandbox.git.configureUser('name', 'email@example.com')
const status = await sandbox.git.status('/app')
await sandbox.git.add('/app')
await sandbox.git.commit('/app', 'my commit')
await sandbox.git.push('/app', { remote: 'origin', branch: 'main' })
await sandbox.process.exec({
command: 'git clone --depth 1 https://github.com/user/repo.git /app',
waitForCompletion: true,
})
await sandbox.process.exec({
command: 'git config user.name "name" && git config user.email "email@example.com"',
workingDir: '/app',
waitForCompletion: true,
})
await sandbox.process.exec({
command: 'git add . && git commit -m "my commit" && git push origin main',
workingDir: '/app',
env: { GIT_TOKEN: 'your-token' },
waitForCompletion: true,
})
Note: Git must be installed in the sandbox image. Most Blaxel base images include git. For private repos, pass credentials via env parameter or configure git credential storage.
MCP integration
E2B provides MCP gateway access via getMcpUrl() / getMcpToken(). Blaxel sandboxes have a built-in MCP server.
TypeScript:
const mcpUrl = sandbox.getMcpUrl()
const mcpToken = sandbox.getMcpToken()
import { blTools } from '@blaxel/vercel'
const tools = await blTools(['sandbox/my-sandbox'])
Python:
mcp_url = sandbox.get_mcp_url()
mcp_token = sandbox.get_mcp_token()
from blaxel.openai import bl_tools
tools = await bl_tools(["sandbox/my-sandbox"])
Key differences
- No API key in code: Blaxel SDK auto-detects credentials from CLI login, .env, env vars, or config file
- Named sandboxes: Blaxel supports
createIfNotExists / create_if_not_exists with a name for idempotent creation; E2B uses opaque auto-generated IDs. Blaxel uses human-readable names, not opaque IDs
- Ports declared at creation: Blaxel requires ports at sandbox creation time; they cannot be added later. Ports 80, 443, 8080 are reserved. E2B exposes all ports implicitly
- Region selection: Blaxel lets you choose a region (
us-pdx-1); E2B does not expose region selection
- Auto scale-to-zero: Blaxel sandboxes auto-pause after ~5s of inactivity and resume in <25ms. No explicit pause/resume needed. E2B requires explicit
pause()/resume() (beta) or createSnapshot()
- Preview URLs vs getHost: Blaxel has a dedicated preview URL system with public/private access control and token-based auth; E2B uses
getHost(port) / get_host(port) which provides public access only (unless secure: true)
- Async by default: Blaxel Python SDK is async-first (all calls use
await); E2B Python SDK is sync by default
- Environment variables: E2B uses a flat object at creation (
envs: { KEY: 'val' }), inherited by all commands. Blaxel uses an array at creation (envs: [{ name: 'KEY', value: 'val' }]) and a flat object per-command (env: { KEY: 'val' }). Blaxel supports secret: true for sensitive values
- Process naming and management: Blaxel processes can be named for later reference (
get, stop, kill, list, wait, logs by name); E2B returns command objects with PIDs
- Log streaming: E2B has
onStdout/onStderr callbacks. Blaxel additionally offers onLog callback, process.streamLogs() with handle (close/wait), and process.logs() with type filtering (stdout/stderr/all)
waitForPorts / wait_for_ports: Blaxel can wait for a port to be open before returning; E2B requires manual polling
- Dev server binding: Dev servers must bind to
0.0.0.0 (not localhost) for preview URLs to work in Blaxel
- ~50% memory reserved for tmpfs: Blaxel uses half of sandbox memory for the in-memory filesystem. Use volumes for extra storage
- No PTY / interactive terminal: E2B has full
sandbox.pty.* API. Blaxel has no interactive terminal support
- No dedicated git API: E2B has
sandbox.git.* for git operations. Blaxel uses process.exec() with git commands
- No sandbox metrics: E2B provides
getMetrics() for CPU/memory/disk usage. Blaxel has no metrics API
- No webhooks/events: E2B has lifecycle events API and webhook registration. Blaxel has no equivalent
- No pre-signed URLs: E2B has
uploadUrl()/downloadUrl() for direct browser-to-sandbox file transfer. Blaxel uses SDK methods (fs.write/fs.read) instead
- Template building: E2B has programmatic
Template.build() with chainable methods. Blaxel uses standard Dockerfiles + bl deploy
- MCP integration: E2B uses
getMcpUrl()/getMcpToken(). Blaxel has a built-in MCP server per sandbox + framework-specific blTools() helpers
- Volumes: Blaxel supports persistent volumes (
VolumeInstance) attached at sandbox creation. E2B does not have a volumes concept
- Code Interpreter: E2B has
runCode() with chart detection. Blaxel has CodeInterpreter class with runCode() and code contexts (no chart detection)
Complete migration example
TypeScript
BEFORE (E2B):
import { Sandbox } from '@e2b/code-interpreter'
const sandbox = await Sandbox.create({
timeoutMs: 600_000,
envs: { NODE_ENV: 'production' },
metadata: { project: 'demo' },
})
await sandbox.files.write('/app/index.js', 'console.log("hello")')
const result = await sandbox.commands.run('node /app/index.js')
console.log(result.stdout)
const cmd = await sandbox.commands.run('cd /app && npm run dev', {
background: true,
onStdout: (data) => console.log(data),
})
const host = sandbox.getHost(3000)
console.log(`Preview: https://${host}`)
await sandbox.commands.kill(cmd.pid)
await sandbox.kill()
AFTER (Blaxel):
import { SandboxInstance } from '@blaxel/core'
const sandbox = await SandboxInstance.createIfNotExists({
name: 'my-sandbox',
image: 'blaxel/node:latest',
region: 'us-pdx-1',
memory: 2048,
ports: [{ target: 3000, protocol: 'HTTP' }],
envs: [{ name: 'NODE_ENV', value: 'production' }],
labels: { project: 'demo' },
ttl: '24h',
})
await sandbox.fs.write('/app/index.js', 'console.log("hello")')
const result = await sandbox.process.exec({
command: 'node /app/index.js',
workingDir: '/app',
waitForCompletion: true,
})
await sandbox.process.exec({
name: 'dev-server',
command: 'npm run dev -- --host 0.0.0.0',
workingDir: '/app',
waitForPorts: [3000],
})
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: 'app-preview' },
spec: { port: 3000, public: true },
})
console.log(`Preview: ${preview.spec?.url}`)
await sandbox.process.kill('dev-server')
await sandbox.delete()
Python
BEFORE (E2B):
from e2b_code_interpreter import Sandbox
sandbox = Sandbox(timeout=600, envs={"NODE_ENV": "production"}, metadata={"project": "demo"})
sandbox.files.write("/app/index.js", 'console.log("hello")')
result = sandbox.commands.run("node /app/index.js")
print(result.stdout)
cmd = sandbox.commands.run("cd /app && npm run dev", background=True,
on_stdout=lambda data: print(data),
)
host = sandbox.get_host(3000)
print(f"Preview: https://{host}")
sandbox.commands.kill(cmd.pid)
sandbox.kill()
AFTER (Blaxel):
import asyncio
from blaxel.core import SandboxInstance
async def main():
sandbox = await SandboxInstance.create_if_not_exists({
"name": "my-sandbox",
"image": "blaxel/node:latest",
"region": "us-pdx-1",
"memory": 2048,
"ports": [{"target": 3000, "protocol": "HTTP"}],
"envs": [{"name": "NODE_ENV", "value": "production"}],
"labels": {"project": "demo"},
"ttl": "24h",
})
await sandbox.fs.write("/app/index.js", 'console.log("hello")')
result = await sandbox.process.exec({
"command": "node /app/index.js",
"working_dir": "/app",
"wait_for_completion": True,
})
await sandbox.process.exec({
"name": "dev-server",
"command": "npm run dev -- --host 0.0.0.0",
"working_dir": "/app",
"wait_for_ports": [3000],
})
preview = await sandbox.previews.create_if_not_exists({
"metadata": {"name": "app-preview"},
"spec": {"port": 3000, "public": True},
})
print(f"Preview: {preview.spec.url}")
await sandbox.process.kill("dev-server")
await sandbox.delete()
asyncio.run(main())
Resources