Before working through the tutorials, it helps to understand a few core concepts — starting with the most common question.
Box types
Why are there different box types?
Every box is the same thing under the hood: a lightweight microVM (a real virtual machine that boots in under a second). The different box types exist for convenience — they bundle a default image and add helper methods so you don’t have to wire things up yourself. Some extend SimpleBox directly (CodeBox, InteractiveBox), while others are standalone wrappers with their own specialized APIs (BrowserBox, ComputerBox).
Here’s what each box type actually is:
| Box type | What it adds | Default image | Image changeable? | Has exec()? |
|---|
| SimpleBox | Shell commands | (you choose) | Yes | Yes |
| CodeBox | run(), install_package() | python:slim | Yes (needs Python) | Yes |
| BrowserBox | connect(), playwright_endpoint() | Playwright (fixed) | No | No |
| ComputerBox | screenshot(), mouse/keyboard | webtop (fixed) | No | No |
| InteractiveBox | PTY terminal session | (you choose) | Yes | Yes |
SimpleBox — the base box type.
- You pick any image, you run shell commands with
exec().
- Image: required in Python, defaults to
python:slim in Node.js.
CodeBox — extends SimpleBox with Python shortcuts.
- Defaults to the
python:slim image (which already has Python inside). Does not install Python — the image already has it.
- Adds
run() (calls python -c for you), install_package() (calls pip install for you), run_script().
- Since CodeBox extends SimpleBox, you still have
exec() too — CodeBox can do everything SimpleBox can.
- Image: changeable, but must have Python inside (e.g.
python:3.11). Without Python, run() will fail.
BrowserBox — a standalone box type for browser automation.
- Uses the Playwright image (
mcr.microsoft.com/playwright:v1.58.0-jammy) which already has Chromium, Firefox, and WebKit inside. Does not install a browser — the image already has them.
- Provides
playwright_endpoint(), endpoint(), connect() to get browser connection URLs.
- Image: fixed, cannot be changed.
ComputerBox — a standalone box type for desktop automation.
- Uses the webtop image (
lscr.io/linuxserver/webtop:ubuntu-xfce) which already has a GUI desktop inside.
- Provides
screenshot(), mouse_move(), left_click(), type(), key() for GUI automation.
- Image: fixed, cannot be changed.
InteractiveBox — extends SimpleBox with a different connection mode.
- Does not add anything to the image. Instead, it changes how the SDK connects: it attaches your terminal directly to the VM’s shell, like SSH. Every Linux image already has a shell.
- Adds
wait() to block until the shell session ends.
- Since InteractiveBox extends SimpleBox, you still have
exec() too.
- Image: required (any OCI image works).
So which one should I use?
| I need to… | Use | Why |
|---|
| Run Python code from an AI agent | CodeBox | run() and install_package() handle Python for you |
| Run shell commands, scripts, or non-Python tools | SimpleBox | Pick any image, use exec() to run anything |
| Control a web browser | BrowserBox | Gives you a ready-to-use Playwright/Puppeteer endpoint |
| Interact with a desktop GUI | ComputerBox | Gives you screenshot, mouse, and keyboard control |
| Use an interactive terminal session | InteractiveBox | Attaches your terminal to the VM like SSH |
Still not sure? Start with CodeBox. It handles the most common AI use case (running untrusted Python) and you can always switch later.
Could I just use SimpleBox for everything?
For CodeBox and InteractiveBox, yes — they extend SimpleBox and you could replicate what they do manually:
# CodeBox does this for you automatically:
async with boxlite.CodeBox() as cb:
output = await cb.run("print(2 + 2)")
# output is "4\n" (run() returns stdout as a string)
# ...but you could do the same thing with SimpleBox:
async with boxlite.SimpleBox(image="python:slim") as box:
result = await box.exec("python", "-c", "print(2 + 2)")
output = result.stdout
# output is "4\n" (exec() returns an ExecResult with .stdout, .stderr, .exit_code)
For BrowserBox and ComputerBox, technically yes but practically no. You could use SimpleBox with the same images (e.g. SimpleBox(image="mcr.microsoft.com/playwright:v1.58.0-jammy")), but you’d have to manually set up port forwarding, start the browser server, wait for it to be ready, and connect — all things that BrowserBox handles in a single connect() call. The specialized APIs (screenshot(), mouse_move(), playwright_endpoint(), etc.) save significant work.
Lifecycle
Every box follows the same lifecycle: create → use → stop.
Context manager (recommended)
The simplest pattern uses async with, which handles startup and cleanup automatically:
async with boxlite.SimpleBox(image="python:slim") as box:
await box.exec("echo", "hello")
# Box is automatically stopped when the block exits
Manual lifecycle
When you need more control (long-lived boxes, cross-function usage), manage the lifecycle explicitly:
box = boxlite.SimpleBox(image="python:slim")
await box.start()
try:
await box.exec("echo", "hello")
finally:
await box.shutdown()
const box = new SimpleBox({ image: 'python:slim' });
try {
const result = await box.exec('echo', 'hello');
console.log(result.stdout);
} finally {
await box.stop();
}
What happens at each stage
| Stage | What happens |
|---|
| Create | BoxLite pulls the OCI image (cached after first use), allocates resources, and boots a microVM. This typically takes under a second for cached images. |
| Use | Run commands with exec() (SimpleBox, CodeBox, InteractiveBox) or run() (CodeBox only). Use specialized methods for BrowserBox (connect()) and ComputerBox (screenshot(), mouse_move(), etc.). Files you create and packages you install persist within the box. Note: each CodeBox.run() call starts a new Python process, so Python variables and function definitions do not carry over between calls. |
| Stop | The VM shuts down and all resources are released. With auto_remove=True (the default), the box is fully cleaned up. |
Images
BoxLite uses standard OCI container images — the same images you use with Docker. For box types that accept a custom image (SimpleBox, CodeBox, InteractiveBox), specify it when creating the box:
# Docker Hub images — use any image you want
boxlite.SimpleBox(image="python:slim")
boxlite.SimpleBox(image="alpine:latest")
boxlite.SimpleBox(image="ubuntu:22.04")
boxlite.SimpleBox(image="node:20-slim")
# CodeBox defaults to python:slim — no image needed
boxlite.CodeBox()
BrowserBox and ComputerBox use fixed images (Playwright and webtop respectively) that can’t be changed, because their convenience methods depend on specific software being pre-installed.
The image is pulled on first use and cached locally. Subsequent starts reuse the cached image.
Use slim or minimal images (python:slim, alpine:latest) for faster boot times. Full images like ubuntu:latest work but are larger and slower to pull.
Resource configuration
Every box accepts CPU and memory parameters. The example below uses SimpleBox/CodeBox/InteractiveBox parameter names:
boxlite.SimpleBox(
image="python:slim",
cpus=2, # CPU cores (default: 1)
memory_mib=4096, # Memory in MiB (default: 2048)
disk_size_gb=10, # Persistent disk in GB (default: ephemeral)
)
| Parameter | Default | Range | Notes |
|---|
cpus | 1 | 1 to host CPU count | More CPUs help with parallel workloads |
memory_mib | 2048 | 128–65536 | Increase for data-heavy workloads or large packages |
disk_size_gb | None (ephemeral) | Any positive integer | Set only if you need data to survive a restart |
BrowserBox and ComputerBox use slightly different parameter names: cpu (singular) and memory (instead of memory_mib). See their SDK reference pages for details.
For most use cases, the defaults work well. Increase memory when running data-heavy code or installing large packages, and add CPUs for compute-intensive workloads.
Security model
Each box is a real microVM — not a container. BoxLite provides multiple layers of isolation:
- Hardware virtualization — KVM on Linux, Hypervisor.framework on macOS. Each box has its own kernel.
- Jailer — restricts the VM process with seccomp filters and cgroups.
- Network isolation — boxes get their own network namespace by default.
You can tune security with SecurityOptions presets:
from boxlite.boxlite import SecurityOptions
async with boxlite.SimpleBox(
image="python:slim",
security=SecurityOptions.maximum(), # Maximum isolation
) as box:
await box.exec("echo", "locked down")
SecurityOptions is currently imported from boxlite.boxlite, not from the top-level boxlite module. Available presets: development(), standard(), maximum().
For full details on the security architecture, see Security.
What’s next?