Your First MicroVM
This guide walks through writing a Nix flake that builds a microVM image, then booting it with mvm.
Understanding the Layers
Section titled “Understanding the Layers”mvm runs a three-layer stack:
Your macOS/Linux Host └── Lima VM (Ubuntu, has /dev/kvm) └── Firecracker microVM (your workload)| Layer | Access command | Has your project files? |
|---|---|---|
| Host | Your normal terminal | Yes |
| Lima VM | mvmctl dev or mvmctl shell | Yes (~ mounted read/write) |
| Firecracker microVM | (headless, no SSH) | No (isolated filesystem) |
Firecracker microVMs are headless workloads with no SSH access — they communicate via vsock only.
Write a Flake
Section titled “Write a Flake”Create a flake.nix in your project:
{ inputs = { mvm.url = "github:auser/mvm?dir=nix"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; };
outputs = { mvm, nixpkgs, ... }: let system = "aarch64-linux"; pkgs = import nixpkgs { inherit system; }; in { packages.${system}.default = mvm.lib.${system}.mkGuest { name = "hello"; packages = [ pkgs.curl ];
services.hello = { command = "${pkgs.python3}/bin/python3 -m http.server 8080"; };
healthChecks.hello = { healthCmd = "${pkgs.curl}/bin/curl -sf http://localhost:8080/"; healthIntervalSecs = 5; healthTimeoutSecs = 3; }; }; };}mkGuest handles everything internally — the Firecracker kernel, busybox init, guest agent, networking, drive mounting, and service supervision are all built into the image automatically. You just define your services and health checks.
Build and Run
Section titled “Build and Run”# Build the image (runs nix build inside the Lima VM)mvmctl build --flake .
# Boot a headless Firecracker VMmvmctl run --flake . --cpus 2 --memory 1024Check Health
Section titled “Check Health”# Ping the guest agentmvmctl vm ping
# Query health check statusmvmctl vm statusRun with Config and Secrets
Section titled “Run with Config and Secrets”Pass custom files to the guest drives:
mkdir -p /tmp/config /tmp/secretsecho '{"port": 8080}' > /tmp/config/app.jsonecho 'API_KEY=sk-...' > /tmp/secrets/app.env
mvmctl run --flake . \ --config-dir /tmp/config \ --secrets-dir /tmp/secretsInside the guest, config files appear at /mnt/config/ and secrets at /mnt/secrets/.
mvmctl stopNext Steps
Section titled “Next Steps”- Writing Nix Flakes — the full
mkGuestAPI - Templates — build once, reuse everywhere
- Config & Secrets — inject files at boot