NanVix MicroVM vs Hyperlight Backends: Isolation Strategies in Microsoft MXC
Microsoft MXC provides two mutually exclusive MicroVM containment backends—NanVix spawns a separate Windows Hypervisor Platform process with full kernel boot overhead, while Hyperlight runs an in-process Unikernel via Rust library integration for significantly faster startup.
The microsoft/mxc repository implements multiple sandboxing strategies for secure code execution, with the NanVix MicroVM and Hyperlight backends representing two distinct approaches to micro-virtualization. Both backends expose the same ContainmentBackend interface to wxc-exec, but they differ fundamentally in process isolation, startup latency, and supported security policies.
Execution Model: Separate Process vs In-Process
NanVix: Full Micro-Kernel VM
The NanVix backend spawns a separate process (nanvixd.exe) that runs a full micro-kernel inside the Windows Hypervisor Platform (WHP). According to the implementation in [src/backends/nanvix/runner/src/lib.rs](https://github.com/microsoft/mxc/blob/main/src/backends/nanvix/runner/src/lib.rs), this launches a lightweight Linux-like kernel that boots a complete guest OS.
Hyperlight: Library-Based Unikernel
In contrast, the Hyperlight backend loads the hyperlight-unikraft-host library in-process within wxc-exec. As implemented in [src/backends/hyperlight/common/src/lib.rs](https://github.com/microsoft/mxc/blob/main/src/backends/hyperlight/common/src/lib.rs), the micro-VM runs as a Rust object inside the same process using the Unikraft Unikernel framework.
Startup Latency and Performance
Cold starts differ dramatically between the two implementations.
NanVix requires a full VM boot sequence with an approximate 60-second timeout for cold starts. While warm-started CBOR snapshots (created via --setup-microvm) reduce this to a few hundred milliseconds, each execution still incurs WHP launch overhead.
Hyperlight eliminates VM boot overhead entirely. Because the Unikernel runs in-process, startup completes in tens of milliseconds. The warm-start concept does not apply here; the micro-VM image loads once and remains reused across executions.
Artifact Provenance and Distribution
Distribution models reflect the architectural split:
- NanVix ships pre-built binaries (
nanvixd.exe,kernel.elf,python3.initrd,nanvix_rootfs.img) as separate files adjacent to the executable. The setup command warms a CBOR snapshot specific to Windows environments. - Hyperlight pulls the micro-VM image from a container registry (
ghcr.io/hyperlight-dev/...) via thehyperlight-commoncrate. No separate binaries ship with the distribution; the image unpacks automatically at setup time via--setup-hyperlight.
Network and Filesystem Policies
Security policies map differently to each backend's capabilities.
Network Isolation
NanVix provides no network stack—the micro-VM remains completely isolated. The implementation explicitly rejects networkPolicy and networkProxy configurations with ERR_NETWORK_POLICY and ERR_PROXY_POLICY errors.
Hyperlight exposes a network stack via Unikraft but disables proxying. While it supports a limited set of network policies, networkProxy requests still generate errors.
Filesystem Restrictions
Both backends enforce strict namespace isolation. The guest observes only its own rootfs image; host paths remain inaccessible (ERR_DENIED_PATHS).
NanVix interprets readwrite_paths and readonly_paths as mount points inside the guest kernel. Hyperlight enforces similar restrictions but explicitly does not support workingDirectory (ERR_WORKDIR).
I/O Handling and Error Management
Standard stream handling diverges based on process architecture.
NanVix closes stdin (Stdio::null) by default while inheriting stdout and stderr. When the environment variable MXC_NANVIX_TRACE=1 is set, the runner captures stderr for diagnostic logging.
Hyperlight uses the host process's standard streams directly. The SDK must explicitly set usePty: false since PTY mode is unsupported.
Error classification also differs:
- NanVix categorizes failures into
NanVixError::Preflight,Platform,Runtime, andTimeout, returningScriptResponsewith sentinel exit code-1. - Hyperlight wraps errors via
hyperlight_commonasHyperlightError, surfacing generic non-zero exit codes.
Configuration and Platform Support
Both backends gate compilation via conditional compilation flags in the source.
Platform Constraints
- NanVix builds only on Windows x86_64 with WHP enabled, gated by
#[cfg(all(feature = "microvm", target_os = "windows"))]. - Hyperlight targets x86_64 (
#[cfg(all(feature = "hyperlight", target_arch = "x86_64"))]) but supports both Windows and Linux for the host process.
JSON Configuration
The parser in [src/core/wxc_common/src/config_parser.rs](https://github.com/microsoft/mxc/blob/main/src/core/wxc_common/src/config_parser.rs) maps containment strings to the ContainmentBackend enum defined in [src/core/wxc_common/src/models.rs](https://github.com/microsoft/mxc/blob/main/src/core/wxc_common/src/models.rs):
// NanVix MicroVM
{ "containment": "microvm" }
// Hyperlight
{ "containment": "hyperlight" }
The CLI entry point in [src/core/wxc/src/main.rs](https://github.com/microsoft/mxc/blob/main/src/core/wxc/src/main.rs) dispatches to NanVixScriptRunner::new() or HyperlightScriptRunner::new() via boxed trait objects.
Implementation Examples
Running Scripts in NanVix
Configure the containment method and warm the snapshot before execution:
{
"process": { "commandLine": "print('Hello from NanVix!')" },
"containment": "microvm"
}
# Optional: Warm-up the CBOR snapshot for faster subsequent runs
wxc-exec --setup-microvm
# Execute
wxc-exec script.json
Running Scripts in Hyperlight
Hyperlight requires initial image setup but no warm-start concept:
{
"process": { "commandLine": "print('Hello from Hyperlight!')" },
"containment": "hyperlight"
}
# Download and unpack the Unikraft image (one-time setup)
wxc-exec --setup-hyperlight
# Execute with in-process startup
wxc-exec script.json
SDK Configuration (TypeScript)
Both backends appear as options in the SandboxingMethod type defined in [sdk/src/types.ts](https://github.com/microsoft/mxc/blob/main/sdk/src/types.ts):
import { MXC } from "mxc-sdk";
const request: MXC.ExecutionRequest = {
process: { commandLine: "print('hello')" },
containment: "microvm", // or "hyperlight"
// For Hyperlight, ensure usePty is disabled
usePty: false
};
const result = await MXC.run(request);
console.log(result.stdout);
Summary
- NanVix MicroVM implements process-level isolation via Windows Hypervisor Platform, requiring full kernel boot (~60s cold start) but providing complete network isolation through a separate
nanvixd.exeprocess. - Hyperlight provides in-process isolation via Unikraft library integration, achieving startup times in tens of milliseconds without separate binaries but with limited network policy support.
- Both backends enforce strict filesystem sandboxing and map to
ContainmentBackend::MicroVmandContainmentBackend::Hyperlightin the core models. - Platform support differs: NanVix requires Windows with WHP, while Hyperlight supports Windows and Linux on x86_64.
- Configuration uses identical JSON keys (
"containment": "microvm"or"hyperlight") parsed inconfig_parser.rs.
Frequently Asked Questions
Which backend offers better isolation security?
NanVix provides stronger isolation by running a full micro-kernel VM in a separate process (nanvixd.exe) with its own memory space and no network stack. Hyperlight runs as a library within the wxc-exec process, relying on Unikernel boundaries rather than hardware virtualization for containment.
Can I use Hyperlight on Linux while NanVix requires Windows?
Yes. The Hyperlight backend compiles on both Windows and Linux x86_64 systems, gated by #[cfg(all(feature = "hyperlight", target_arch = "x86_64"))]. NanVix is restricted to Windows x86_64 only with the Windows Hypervisor Platform enabled.
Why does NanVix have a 60-second timeout while Hyperlight starts instantly?
NanVix performs a full VM boot sequence including kernel initialization and rootfs mounting within the WHP hypervisor, justifying the 60-second timeout for cold starts. Hyperlight loads a pre-built Unikraft image in-process as a Rust object, eliminating boot overhead entirely and reducing startup to tens of milliseconds.
How do I configure filesystem access for each backend?
Both backends map readwrite_paths and readonly_paths to guest mount points rather than host directories. NanVix mounts these within its Linux-like kernel, while Hyperlight applies them within the Unikraft namespace. Neither supports direct host path access (ERR_DENIED_PATHS), and Hyperlight specifically rejects workingDirectory configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →