Skip to main content

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
1

Check for explicit override

If you pass backend="firecracker" to SmolVM(), that’s used
2

Check SMOLVM_BACKEND env var

export SMOLVM_BACKEND=qemu
3

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

# 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
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

Performance Characteristics

From README.md:168, benchmarked on AMD Ryzen 7 7800X3D:
MetricFirecracker
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

# 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.

Performance Characteristics

QEMU is slower than Firecracker but still usable for development:
MetricQEMU (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

FeatureFirecrackerQEMU
PlatformLinux onlyLinux, macOS, Windows
HypervisorKVMKVM, HVF, WHPX, TCG
Boot Time~500ms~2-3s
Memory Overhead~5MB~50MB
NetworkingTAP devicesUser-mode (SLIRP)
Guest IPDynamic (172.16.0.x)Fixed (10.0.2.15)
Concurrent VMs100+ (limited by memory)Limited (IP conflict)
Production ReadyYes (AWS Lambda)Development only
Setup ComplexityHigh (sudo, TAP, nftables)Low (just install QEMU)

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

# 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
# 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
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

Build docs developers (and LLMs) love