Frequently asked questions about BoxLite. Fixes for specific errors are in Troubleshooting.
BoxLite is an embeddable virtual machine runtime for secure, isolated code execution. Think of it as "SQLite for sandboxing" - a lightweight library you can embed directly in your application without requiring a daemon or root privileges.
| Feature | BoxLite | Docker |
|---|---|---|
| Isolation | Hardware VM (KVM/Hypervisor.framework) | Container (namespaces/cgroups) |
| Daemon | No daemon required | Requires Docker daemon |
| Root | No root required | Typically needs root/sudo |
| Architecture | Embeddable library | Client-server architecture |
| Use Case | Embedded sandboxing, AI agents | Application deployment, CI/CD |
| Startup | ~1-2 seconds | ~100-500ms |
| Isolation Level | Separate kernel, hardware isolation | Shared kernel |
When to use BoxLite:
- AI agents that need full execution freedom
- Untrusted code execution
- Hardware-level isolation required
- Embedded in applications (no daemon)
When to use Docker:
- Application deployment
- Development environments
- CI/CD pipelines
- Established Docker workflows
No. BoxLite doesn't require root privileges.
macOS: Hypervisor.framework is available to all users (no special permissions)
Linux: Only requires access to /dev/kvm, which can be granted through group membership:
sudo usermod -aG kvm $USER
# Logout and login for changes to take effectYes, through WSL2 (Windows Subsystem for Linux).
Requirements:
- Windows 10 version 2004+ or Windows 11
- WSL2 with a Linux distribution (Ubuntu recommended)
- KVM support enabled in WSL2
Setup:
# Inside WSL2, add your user to the kvm group
sudo usermod -aG kvm $USER
# Apply the new group membership (pick one):
newgrp kvm
# OR restart WSL from Windows PowerShell:
# wsl.exe --shutdown
# Verify KVM access
python3 -c "open('/dev/kvm','rb').close(); print('kvm ok')"Common Issue: If you see "Timeout waiting for guest ready (30s)" errors, your shell cannot open /dev/kvm. This happens when:
/dev/kvmis owned byroot:kvmwith mode660- Your user is not in the
kvmgroup
Run sudo usermod -aG kvm $USER and restart WSL with wsl.exe --shutdown.
Note: Native Windows (without WSL2) is not supported. BoxLite requires KVM (Linux) or Hypervisor.framework (macOS).
Python 3.10 or later.
Check your version:
python --version # Should be 3.10+Upgrade if needed:
# macOS (Homebrew)
brew install python@3.11
# Ubuntu/Debian
sudo apt install python3.11
# Or use pyenv
pyenv install 3.11.0Yes. BoxLite is stable and used in production.
Production considerations:
- ✅ Stable API
- ✅ Hardware-level isolation
- ✅ Resource limits enforced
- ✅ Error handling robust
⚠️ Monitor resource usage⚠️ Test at expected scale⚠️ Configure appropriate limits
See Deployment Patterns for production checklist.
Apache License 2.0. Free for commercial and non-commercial use.
See LICENSE for details.
macOS: Hypervisor.framework (built into macOS 12+)
Linux: KVM (Kernel-based Virtual Machine)
How it works:
- BoxLite uses libkrun as the hypervisor abstraction
- libkrun provides a unified API over Hypervisor.framework (macOS) and KVM (Linux)
- Each box runs as a separate microVM with its own kernel
Minimum: 128 MiB (configured via memory_mib)
Default: 512 MiB
Range: 128 MiB to 64 GiB (65536 MiB)
Overhead:
- VM overhead: ~50-100 MB per box
- Guest kernel: ~20-40 MB
- Container: Depends on image
Example:
# Lightweight box
boxlite.BoxOptions(memory_mib=128) # Minimum for Alpine
# Standard box
boxlite.BoxOptions(memory_mib=512) # Default, good for Python
# Heavy box
boxlite.BoxOptions(memory_mib=2048) # For complex workloadsTypical: 1-2 seconds
Factors:
- Image size (cached vs first pull)
- Disk I/O speed
- Available resources
First run: 5-30 seconds (includes image pull)
Subsequent runs: 1-2 seconds (image cached)
Optimization:
- Pre-pull images:
await runtime.images.pull("...") - Reuse boxes instead of creating new ones
- Use smaller base images (
alpine:latestvsubuntu:latest)
Yes. Keep a box after stop to keep its disk, or mount a volume to share data between boxes.
Default:
boxlite.BoxOptions() # The box and its disk are removed when it stopsKept after stop:
boxlite.BoxOptions(
disk_size_gb=10, # 10 GB QCOW2 disk
auto_delete=0, # keep the box after stop
)
# Data survives stop/restart
await box.stop()
# ... later ...
box = await runtime.get(box_id) # Disk intactAlso:
- Use volume mounts for host-box data sharing
- Read-write volumes persist changes to host filesystem
1. Enable debug logging:
RUST_LOG=debug python script.py2. Check box status:
info = await box.info()
print(f"Status: {info.state.status}")
metrics = await box.metrics()
print(f"Memory: {metrics.memory_usage_bytes / (1024**2):.2f} MB")3. Inspect filesystem:
# Check disk space
df -h ~/.boxlite
# Check box data
ls -la ~/.boxlite/boxes/
# Check image cache
ls -la ~/.boxlite/images/4. Check hypervisor:
# Linux
ls -l /dev/kvm
lsmod | grep kvm
# macOS
sw_vers # Should be 12+
uname -m # Should be arm64See Debugging Guide for comprehensive troubleshooting.
Yes. All boxes have full internet access by default.
Outbound connections:
- HTTP/HTTPS requests
- DNS resolution
- Any protocol (TCP/UDP)
Example:
async with boxlite.SimpleBox(image="alpine:latest") as box:
# Test internet access
result = await box.exec("wget", "-O-", "https://api.github.com/zen")
print(result.stdout)Use the ports parameter for port forwarding:
boxlite.BoxOptions(
ports=[
(8080, 80, "tcp"), # Host 8080 → Guest 80
(5432, 5432, "tcp"), # PostgreSQL
{"guest_port": 3000}, # OS-selected host port
]
)Access from host:
curl http://localhost:8080Port publication is local-only and TCP-only. It creates a listener that ordinary
host applications can use for repeated connections. Remote runtimes reject
ports; use box.network.tunnel(...) with the service address for portable SDK access. Each tunnel is
a prepared one-shot connection; call forward() to turn it into a listener.
Image EXPOSE declarations do not publish host ports.
See Configuring Networking for details.
Not directly. Boxes are isolated from each other.
Alternatives:
-
Share data via volumes:
volumes=[("/host/shared", "/mnt/shared", False)]
-
Use host network:
- Box A exposes port
- Box B connects to
host.boxlite.internal:port - With an empty
allow_net, host loopback services are reachable from inside the box; a non-emptyallow_netmust list"192.168.127.254"or a CIDR covering it
-
External service:
- Both boxes connect to Redis/database on host or network
Common causes:
-
Insufficient resources:
# Increase limits boxlite.BoxOptions( cpus=4, # More CPUs memory_mib=4096, # More memory )
-
Disk I/O:
- Check host disk speed:
dd if=/dev/zero of=test bs=1M count=1024
- Check host disk speed:
-
Too many boxes:
metrics = await runtime.metrics() print(f"Active boxes: {metrics.active_boxes}") # Reduce concurrency or increase host resources
-
Image size:
- Use smaller images:
alpine:latest(5 MB) vsubuntu:latest(77 MB) - Check image size:
docker images
- Use smaller images:
It depends on host resources.
Resource calculation:
Total Memory = (boxes * memory_mib) + overhead
Total CPUs = boxes * cpus (can oversubscribe)
Example:
100 boxes * 512 MiB = 51.2 GB memory needed
100 boxes * 1 CPU = 100 CPUs (oversubscribed, shares-based)
Best practices:
- Start small (10 boxes) and scale up
- Monitor metrics:
(await runtime.metrics()).active_boxes - Use resource pooling (reuse boxes)
- Test at expected load
Example:
import asyncio
async def run_100_boxes():
tasks = []
for i in range(100):
task = run_box(i)
tasks.append(task)
results = await asyncio.gather(*tasks)No hard limit, but practical constraints:
Memory:
- Range: 128 MiB to 64 GiB (65536 MiB)
- Limited by host RAM
Disk:
- Range: 1 GB to 1 TB
- Limited by host storage
CPUs:
- Range: 1 to 16 (the bundled guest kernel brings up at most 16 vCPUs)
- Can oversubscribe (shares-based)
Tested configurations:
- ✅ 64 GiB memory
- ✅ 1 TB disk
- ✅ 16 CPUs
Documentation:
- Getting Started - Quick onboarding
- Python SDK README - Complete Python API
- Guides - Practical guides
- Reference - API and configuration reference
- Concepts - How BoxLite works
Community:
- GitHub Issues - Bug reports and feature requests
- GitHub Discussions - Questions and community support
Before posting:
- Check this FAQ
- Search existing issues/discussions
- Enable debug logging:
RUST_LOG=debug - Include BoxLite version, platform, and minimal reproduction
1. Search existing issues: GitHub Issues
2. Gather information:
- BoxLite version:
python -c "import boxlite; print(boxlite.__version__)" - Platform:
uname -a - Python version:
python --version - Error message and stack trace
3. Minimal reproduction:
import asyncio
import boxlite
async def reproduce():
# Minimal code that reproduces the issue
async with boxlite.SimpleBox(image="python:slim") as box:
result = await box.exec("command")
asyncio.run(reproduce())4. Debug logs:
RUST_LOG=debug python reproduce.py 2>&1 | tee debug.log5. Create issue:
- Use bug report template
- Include all gathered information
- Attach debug logs if relevant
- Be specific and clear
1. Check roadmap:
- Review GitHub Issues with
enhancementlabel
2. Search for similar requests:
- May already be planned or discussed
3. Create feature request:
- Use feature request template
- Describe use case (why you need it)
- Provide examples of desired API/behavior
- Explain benefits to other users
4. Participate in discussion:
- Respond to questions
- Refine proposal based on feedback
- Consider implementing it yourself (see CONTRIBUTING.md)
See CONTRIBUTING.md for:
- Development setup
- Running tests
- Code style guidelines
- Pull request process
Quick start:
git clone https://github.com/boxlite-ai/boxlite.git
cd boxlite
git submodule update --init --recursive
make setup
make dev:pythonAreas to contribute:
- Bug fixes
- Documentation improvements
- New examples
- SDK improvements (Python, Node.js, C)
- Performance optimizations