systems

NixVM: a durable explainer for Nix-based virtual machine management

NixVM is a declarative approach to managing virtual machines by treating VM configurations and images as versioned, reproducible artifacts built on the Nix package manager. Inst...

Mara Ellison
NixVM: a durable explainer for Nix-based virtual machine management

NixVM is a declarative approach to managing virtual machines by treating VM configurations and images as versioned, reproducible artifacts built on the Nix package manager. Instead of manually editing guest settings or imaging disks, you define machine states in Nix and materialize them consistently across hosts. This explainer covers core concepts, practical workflows, configuration patterns, integration options, and how NixVM relates to alternatives, with an emphasis on stability, composability, and auditability for long-lived infrastructure.

What NixVM is and who it is for

NixVM is a set of patterns and tooling that brings Nix reproducibility to virtual machines, whether you run them locally with QEMU or KVM or provision servers in a cloud or data center. It is useful when you need to reliably recreate identical environments, roll back to prior states, or manage many similar but slightly different VMs without configuration drift. Typical users include development teams, CI pipelines, and operations engineers who already rely on Nix for deterministic builds and want the same guarantees for infrastructure. While not a standalone hypervisor, NixVM complements solutions like NixOS, Docker, and cloud images by keeping VM artifacts declarative and versioned.

How NixVM works at a high level

At its core, NixVM encodes a virtual machine as a Nix derivation or flake that specifies the disk image, kernel, firmware, cloud-init data, and any baked-in packages and configuration. When you build or activate a VM definition, Nix computes a unique store address based on its exact contents; changing any file, package, or setting produces a different address and a new artifact. You can instantiate multiple VM derivations from a common base by overriding a small set of attributes, which keeps storage efficient while letting each variant remain immutable and traceable. NixVM workflows typically integrate with existing hypervisor tooling rather than replacing it, using Nix to drive QEMU/KVM, LXD, or cloud providers through declarative specifications.

Derivation-based images and address-based caching

Because each VM image is a Nix store artifact, you get automatic deduplication and content addressing. Two VMs that share the same base image and diverge only in a few overlay layers can reuse most of the same underlying store objects, saving disk space. Rollbacks are essentially pointer switches to an earlier store path, which makes recovery fast and deterministic. This model also enables reliable caching in shared environments, since the address changes only when the full dependency tree changes. For teams, this means centrally stored paths can be fetched once and reused across machines and CI runners without rebuilding everything from scratch.

Key concepts and terminology

  • Declarative VM definition: A Nix expression or flake that specifies everything needed to instantiate a VM.
  • Store derivation: A content-addressed unit that produces a VM disk, kernel, and configuration bundle.
  • Overlay or diff layer: A writable layer on top of a shared base image for stateful changes.
  • Flake inputs: External sources such as nix-community modules, shared flakes, or package sets that compose into your VM definition.
  • Activation: The process of instantiating a derivation to create or start a VM using a hypervisor backend.

Basic workflows and practical examples

To use NixVM in practice, you start with a base module that defines a minimal VM, then extend it with packages, users, services, and network settings. A simple local workflow might express a VM as a NixOS-like configuration with hardware virtualization options, from which you build an image and launch it via QEMU. In more advanced setups, you parameterize VMs with environment-specific overlays so you can generate staging, testing, and production variants from a single source of truth. You can also integrate NixVM definitions into CI so that every merge produces a fresh, addressable VM artifact for integration tests. Because the definitions are code, you can lint them, review diffs, and keep them in the same repository as application code.

Example patterns (conceptual, not prescriptive)

Below is a simplified comparison of how similar VMs might be expressed with different goals in mind. Exact module names and options depend on your tooling and hypervisor choices.

VM purposeCore attributesUse case
Development workstationMinimal base packages, user config, shared folders, forwarded portsDaily interactive use with quick iteration
CI runnerHardened image, no persistent user state, cleanup on shutdownEphemeral builds and tests, reproducible results
Staging serverNear-production packages, monitoring agents, read-only except logsPre-production validation and performance checks
Reference golden imageLocked package set, signed configurations, baseline security settingsStandard baseline for clones and audits

Integration and deployment options

NixVM does not mandate a single deployment path; it works alongside existing virtualization and cloud ecosystems. Locally, you can drive QEMU or KVM through NixOS module options or libvirt-derived tooling, storing VM artifacts in the Nix store or exporting them to disk images for other platforms. In data centers, you can combine Nix-defined images with tools like LXD, cloud-init, or infrastructure-as-code pipelines that consume Nix-built artifacts. Because the definitions are portable, you can version them in Git, generate images for multiple hypervisors, and apply the same declarative patches across environments. This makes it easier to audit changes, reproduce incidents, and keep configurations synchronized without manual diff-and-apply steps.

How NixVM relates to alternatives

NixVM is one approach among many for reproducible infrastructure, and it is most powerful when positioned within your broader stack rather than treated as a drop-in replacement for everything. Below is a concise relationship map to clarify tradeoffs and typical fit scenarios.

Declarative host OS with live configuration management
ApproachScope of reproducibilityTypical tradeoffs
NixVM (with QEMU/KVM)VM disk and guest configuration as Nix derivationsStrong isolation, higher resource cost; best where full-OS reproducibility matters
NixOS on dedicated hardware or in cloudLower overhead than VMs; limited by host kernel sharing
Docker containersProcess-level isolation and image reproducibilityLightweight and fast; less isolation and different security model
Packer or cloud AMI pipelinesImage-building automation, often imperativeGood for existing CI/CD; can diverge from source config unless codified in Nix
Terraform for infrastructureResource and network topology as codeExcellent for orchestration; does not manage OS packages or configs by itself

In practice, teams often combine approaches: use NixVM for critical development and test VMs, NixOS for production servers, and container images for microservices. Keeping these definitions in the same Nix codebase reduces divergence and makes rollbacks and audits more straightforward.

Operational considerations and limitations

NixVM introduces new operational patterns you need to manage, such as deciding where store paths live, how to handle secrets, and how to integrate with provisioning and monitoring tools. Storage can grow if you retain many VM derivations, so consider retention policies and periodic garbage collection. Because hypervisor backends vary, not every NixVM feature works identically across QEMU, KVM, LXD, or cloud providers; you should validate device and networking behavior for your target environment. Finally, treat VM definitions as code: review diffs, include them in CI, and version them so you can reliably reproduce state and understand who changed what and when.