Backend Overview
SmolVM supports two virtualization backends, each optimized for different platforms:
Firecracker Linux-only , KVM-based microVM runtime built by AWS
Sub-second boot times
Minimal resource overhead (~5MB per VM)
Production-grade isolation (used by AWS Lambda)
Requires /dev/kvm access
QEMU Cross-platform traditional VM emulator
Works on macOS (Hypervisor.framework) and Linux
User-mode networking (no TAP devices)
Broader hardware compatibility
Slower than Firecracker but more portable
Auto-Detection
SmolVM automatically selects the best backend for your platform (see src/smolvm/backends.py:29):
def resolve_backend ( requested : str | None = None ) -> str :
"""Resolve the effective backend name.
Resolution order:
1) Explicit ``requested`` argument.
2) ``SMOLVM_BACKEND`` environment variable.
3) Platform-aware default (Darwin -> qemu, others -> firecracker).
"""
if platform.system().lower() == "darwin" :
return BACKEND_QEMU
return BACKEND_FIRECRACKER
Check for explicit override
If you pass backend="firecracker" to SmolVM(), that’s used
Check SMOLVM_BACKEND env var
export SMOLVM_BACKEND = qemu
Platform detection
macOS (Darwin) → QEMU (KVM not available)
Linux → Firecracker (optimal performance)
Other → Firecracker (may fail if KVM unavailable)
Best Practice : Let SmolVM auto-detect unless you have a specific reason to override. The defaults are optimized for each platform.
Firecracker Backend
Architecture
Firecracker is a minimalist Virtual Machine Monitor (VMM) built in Rust:
KVM-based : Uses Linux Kernel-based Virtual Machine for hardware virtualization
Minimal device model : Only virtio-net, virtio-block, and virtio-vsock
API-driven : Configured via Unix socket REST API
Process-per-VM : Each VM runs as a separate Firecracker process
┌──────────────────────────────────────┐
│ SmolVM (Python) │
│ - VMConfig │
│ - NetworkManager │
│ - StateManager │
└────────────┬─────────────────────────┘
│ FirecrackerClient (HTTP over Unix socket)
▼
┌──────────────────────────────────────┐
│ Firecracker Process (VMM) │
│ - /tmp/firecracker-vm-abc.sock │
│ - TAP device: tap-smol-abc │
│ - Memory: 512 MiB (default) │
└────────────┬─────────────────────────┘
│ KVM ioctls
▼
┌──────────────────────────────────────┐
│ /dev/kvm (Linux Kernel) │
│ - Hardware virtualization (VT-x/AMD-V)
│ - Memory management (EPT/NPT) │
└──────────────────────────────────────┘
Prerequisites
Linux (Ubuntu/Debian)
Linux (Fedora/RHEL)
# 1. Check KVM support
lsmod | grep kvm
# Should show: kvm_intel or kvm_amd
# 2. Run system setup
sudo ./scripts/system-setup.sh --configure-runtime
# This installs:
# - Firecracker binary (downloaded to ~/.local/bin/firecracker)
# - iproute2, nftables (for networking)
# - Configures sudo permissions for ip/nft commands
# Install KVM and dependencies
sudo dnf install qemu-kvm libvirt nftables iproute
# Add user to kvm group
sudo usermod -aG kvm $USER
newgrp kvm
# Run SmolVM setup
sudo ./scripts/system-setup.sh --configure-runtime
KVM Requirement : Firecracker requires /dev/kvm access. On cloud VMs, ensure nested virtualization is enabled:
AWS : Use metal instances or enable nested virt on Nitro instances
GCP : Use --enable-nested-virtualization flag
Azure : N-series VMs support nested virtualization
From README.md:168, benchmarked on AMD Ryzen 7 7800X3D:
Metric Firecracker VM Create + Start ~572ms SSH Ready ~2.1s Command Execution ~43ms VM Stop + Delete ~751ms Full Lifecycle ~3.5s
Firecracker is optimized for density and latency. AWS Lambda uses it to run millions of concurrent functions.
Networking
Firecracker uses TAP devices for networking (see Networking Concepts ):
TAP device per VM : tap-smol-{vm_id[:8]}
Host IP : 172.16.0.1 (TAP device side)
Guest IP : Auto-assigned from 172.16.0.0/16 range
NAT : Configured via nftables for internet access
SSH : Port forwarding via nftables DNAT
from smolvm import SmolVM
with SmolVM( backend = "firecracker" ) as vm:
print (vm.network_config.guest_ip) # e.g., "172.16.0.2"
print (vm.network_config.tap_device) # e.g., "tap-smol-abc123de"
QEMU Backend
Architecture
QEMU is a mature, feature-rich emulator/virtualizer:
Cross-platform : Works on Linux (KVM) and macOS (Hypervisor.framework)
Full system emulation : Can emulate different CPU architectures
User-mode networking : Built-in NAT via SLIRP (no TAP devices)
Heavier : ~50MB overhead per VM vs Firecracker’s ~5MB
┌──────────────────────────────────────┐
│ SmolVM (Python) │
│ - VMConfig │
│ - SSH client │
└────────────┬─────────────────────────┘
│ subprocess (qemu-system-*)
▼
┌──────────────────────────────────────┐
│ QEMU Process │
│ - User networking (SLIRP) │
│ - SSH port: localhost:random │
│ - Guest IP: 10.0.2.15 (fixed) │
│ - Memory: 512 MiB (default) │
└────────────┬─────────────────────────┘
│ Hypervisor API
▼
┌──────────────────────────────────────┐
│ macOS: Hypervisor.framework (hvf) │
│ Linux: KVM (/dev/kvm) │
└──────────────────────────────────────┘
Prerequisites
macOS (Homebrew)
Linux (fallback)
# Install QEMU
brew install qemu
# Run SmolVM setup (downloads kernel/rootfs)
./scripts/system-setup-macos.sh
# Verify QEMU has hvf support
qemu-system-aarch64 -accel help | grep hvf
# Should show: hvf
macOS 10.10+ includes Hypervisor.framework. No additional setup needed.
# Install QEMU
sudo apt-get install qemu-system-x86 qemu-system-aarch64
# Force QEMU backend
export SMOLVM_BACKEND = qemu
# Run setup
./scripts/system-setup.sh --configure-runtime
On Linux, Firecracker is preferred. Only use QEMU if KVM is unavailable (e.g., nested virtualization disabled).
QEMU is slower than Firecracker but still usable for development:
Metric QEMU (estimated) VM Create + Start ~2-3s SSH Ready ~5-8s Command Execution ~50-100ms VM Stop ~1-2s Full Lifecycle ~10-15s
Performance Note : QEMU is 3-4x slower than Firecracker for VM lifecycle operations. For high-frequency agent workflows (100+ VM creates/destroys), prefer Firecracker on Linux.
Networking
QEMU uses user-mode networking (SLIRP) (see src/smolvm/vm.py:54):
No TAP devices : Networking is handled inside QEMU process
Fixed guest IP : 10.0.2.15 (all VMs share this IP)
Gateway : 10.0.2.2 (QEMU built-in)
DNS : 10.0.2.3 (QEMU DNS forwarder)
SSH : Port forwarding via QEMU -netdev hostfwd
from smolvm import SmolVM
with SmolVM( backend = "qemu" ) as vm:
print (vm.network_config.guest_ip) # Always "10.0.2.15"
print (vm.network_config.gateway_ip) # Always "10.0.2.2"
print (vm.network_config.ssh_host_port) # Random port, e.g., 45678
QEMU Command Line
From src/smolvm/vm.py:864, SmolVM generates QEMU commands like:
qemu-system-aarch64 \
-machine virt,accel=hvf,gic-version= 3 \
-cpu host \
-smp 2 \
-m 512 \
-kernel /path/to/kernel \
-drive file=/path/to/rootfs.ext4,if=virtio,format=raw \
-append "console=ttyAMA0 root=/dev/vda rw" \
-netdev user,id=net0,hostfwd=tcp::45678-:22 \
-device virtio-net-pci,netdev=net0 \
-nographic \
-serial mon:stdio
Key parameters:
-accel hvf : Use macOS Hypervisor.framework (or kvm on Linux)
-netdev user,hostfwd=... : User networking with SSH port forwarding
-nographic : No graphical console (headless)
Backend Comparison
Feature Matrix
Use Cases
Limitations
Feature Firecracker QEMU Platform Linux only Linux, macOS, Windows Hypervisor KVM KVM, HVF, WHPX, TCG Boot Time ~500ms ~2-3s Memory Overhead ~5MB ~50MB Networking TAP devices User-mode (SLIRP) Guest IP Dynamic (172.16.0.x) Fixed (10.0.2.15) Concurrent VMs 100+ (limited by memory) Limited (IP conflict) Production Ready Yes (AWS Lambda) Development only Setup Complexity High (sudo, TAP, nftables) Low (just install QEMU)
When to Use Firecracker Production AI agent workloads on Linux servers
High-density scenarios (100+ concurrent VMs)
Low-latency requirements (sub-second boot)
CI/CD on Linux runners with KVM
When to Use QEMU macOS development (only option)
Cloud VMs without KVM (nested virt disabled)
Quick testing without system setup
Cross-platform compatibility needs
Firecracker Limitations Requires Linux with KVM support
Needs root/sudo for TAP device creation
More complex network setup (nftables)
QEMU Limitations 3-4x slower VM lifecycle than Firecracker
Fixed guest IP prevents multiple concurrent VMs from having unique addresses
Higher memory overhead (~50MB vs ~5MB)
Not recommended for production agent workloads
Overriding the Backend
Option 1: Environment Variable
# Force QEMU on Linux (for testing)
export SMOLVM_BACKEND = qemu
python your_agent.py
# Force Firecracker (will fail on macOS)
export SMOLVM_BACKEND = firecracker
python your_agent.py
Option 2: Constructor Argument
from smolvm import SmolVM
# Explicit backend selection
with SmolVM( backend = "qemu" ) as vm:
print (vm.backend) # "qemu"
# Auto-detect (recommended)
with SmolVM( backend = "auto" ) as vm:
print (vm.backend) # "firecracker" on Linux, "qemu" on macOS
Option 3: VMConfig
from smolvm import SmolVM, VMConfig
config = VMConfig(
vm_id = "my-vm" ,
backend = "firecracker" ,
mem_size_mib = 2048 ,
vcpu_count = 4
)
with SmolVM( config = config) as vm:
print (vm.backend) # "firecracker"
Recommendation : Omit the backend parameter and let SmolVM auto-detect. This ensures your code works across platforms.
Validating Backend Support
Use the smolvm doctor command to check prerequisites:
# Auto-detect and validate current platform
smolvm doctor
# Force check specific backend
smolvm doctor --backend firecracker
smolvm doctor --backend qemu
# CI-friendly JSON output
smolvm doctor --json --strict
Example output:
{
"platform" : "darwin-arm64" ,
"backend" : "qemu" ,
"checks" : [
{
"name" : "qemu" ,
"status" : "ok" ,
"detail" : "qemu-system-aarch64 (/opt/homebrew/bin/qemu-system-aarch64)"
},
{
"name" : "qemu-accel" ,
"status" : "ok" ,
"detail" : "hvf accelerator available"
}
]
}
Troubleshooting
Firecracker: /dev/kvm permission denied
# Check KVM permissions
ls -la /dev/kvm
# Should show: crw-rw---- 1 root kvm
# Add your user to kvm group
sudo usermod -aG kvm $USER
newgrp kvm
# Verify
groups | grep kvm
QEMU: No accelerator found
# Check QEMU acceleration support
qemu-system-x86_64 -accel help
# macOS: Should show "hvf"
# Linux: Should show "kvm"
# If missing on macOS, reinstall QEMU:
brew reinstall qemu
# If missing on Linux, install KVM:
sudo apt-get install qemu-kvm
Backend auto-detection wrong
SmolVM uses platform.system() to detect the OS. If detection fails: import platform
print (platform.system()) # Should be "Darwin" or "Linux"
# Workaround: Explicitly set backend
export SMOLVM_BACKEND = qemu
Check kernel/rootfs compatibility: # Verify files exist
ls -lh ~/.local/share/smolvm/
# Should show: kernel, rootfs.ext4
# Re-download images
rm -rf ~/.local/share/smolvm/
./scripts/system-setup-macos.sh # or system-setup.sh on Linux
Next Steps
Installation Guide Detailed setup instructions for each backend
Architecture Overview Learn how microVMs work under the hood
Networking Understand TAP devices vs user-mode networking