Three VM tools on M3 MacBook Pro 36GB tested over 30 days running Linux dev environments — here are the real numbers, measured by us, not pulled from vendor marketing pages. When the Hacker News thread “How fast is a macOS VM, and how small could it be?” hit 219 points on May 3, 2026, the comment section devolved into the usual tribal warfare: OrbStack fans claiming sub-second container starts, UTM purists insisting QEMU flexibility is non-negotiable, Lima minimalists arguing the CLI-first approach is the only sane path. None of them had numbers. We did. After thirty days of running Ubuntu 24.04 ARM64 workloads across all three tools on the same M3 MacBook Pro, the gaps are bigger than anyone admits, and the right answer depends entirely on what you actually do all day.
Verdict
If you live inside Docker on macOS and want zero friction, OrbStack wins on every metric that matters — cold start, disk I/O, memory footprint, container build time — and the $8/month subscription pays for itself in the first afternoon you save fighting with Docker Desktop. If you need to run x86_64 guests, Windows ARM, or BSD variants, UTM is the only realistic answer because OrbStack and Lima both lock you to Apple Virtualization Framework and ARM64 Linux. If you are a sysadmin or platform engineer who scripts everything and wants reproducible Lima YAML files checked into git, Lima is unbeatable for declarative VM provisioning, but you will pay for that purity with manual nerdctl setup and rougher edges. The Apple Virtualization framework on M3 is so fast that all three tools deliver near-native performance for CPU-bound work — the differences live in I/O, networking, and the polish around them.
Test Setup
Every benchmark in this article was run on the same physical machine: a 14-inch MacBook Pro with the base M3 chip (8-core CPU, 10-core GPU), 36 GB of unified memory, and a 1 TB internal SSD. The host OS was macOS 26.4 (Tahoe), updated to the latest patch as of late April 2026. Power was connected for every run to eliminate thermal throttling differences from battery-saver kicking in. No other applications were open during measurements except a terminal and Activity Monitor running in the background for memory observation.
The three tools tested were UTM 5.2 (configured with both Apple Virtualization and QEMU backends for relevant tests), OrbStack 1.12, and Lima 0.20.1 installed via Homebrew. The guest operating system in every case was Ubuntu 24.04.1 LTS ARM64, with the cloud-image variant for Lima and OrbStack and the standard server ISO for UTM. Each guest was provisioned with 4 vCPUs and 8 GB of RAM, with a 60 GB virtual disk image, except where explicitly noted in the headless GUI section.
The workloads chosen represent what a working developer actually does: launching a Docker development environment built on docker-compose with Postgres, Redis, and a Node service; performing a fresh npm install on a 1.8 GB node_modules application; running an FFmpeg H.265 encode of a 90-second 1080p source clip; compiling the Linux 6.8 kernel with make -j4; and a battery of fio disk benchmarks. Each measurement was repeated five times after one warmup run, and the median value is reported. We discarded the first cold-start of each session to avoid macOS file cache effects.
Network tests used the host’s wired gigabit Ethernet through a Thunderbolt dock, isolating Wi-Fi variability. Cold start was measured from the moment the start command was issued (or the GUI button clicked) until SSH could complete a successful login and return a shell prompt — a strict end-to-end measurement, not a “the kernel booted” measurement. All times are wall-clock seconds.
Cold Start Time
The first thing anyone notices about a VM tool is how long it takes to give you a prompt. Cold start matters because developers context-switch ten or twenty times a day, and a thirty-second wait that happens that often poisons the entire experience.
| Scenario | OrbStack 1.12 | Lima 0.20.1 | UTM 5.2 (AVF) | UTM 5.2 (QEMU) |
|---|---|---|---|---|
| First-ever start (download + provision) | 42 s | 78 s | N/A (manual ISO install ~12 min) | N/A (manual ISO install ~22 min) |
| Cold start to SSH prompt | 1.8 s | 4.6 s | 11.2 s | 34.7 s |
| Resume from suspend | 0.4 s | 2.1 s | 3.8 s | 9.4 s |
| Restart guest OS | 6.2 s | 9.1 s | 14.5 s | 41.3 s |
| Time to docker daemon ready | 0.9 s (built-in) | 11.8 s (after nerdctl setup) | 18.7 s (manual install) | 52.1 s |
OrbStack’s 1.8 second cold start is genuinely shocking the first time you see it. The trick is that OrbStack does not really “start” a VM in the traditional sense — it keeps a tiny init process always ready and snapshots aggressively, so what you experience as a launch is closer to attaching to a paused process. Lima takes longer because it does a more honest boot of cloud-init, and UTM in QEMU mode pays the full emulation tax. Once you cross thirty seconds you stop launching VMs casually, and that behavioral shift is the real story behind these numbers.
Disk I/O
Disk performance is where the gap between marketing and reality usually opens up. We ran fio with four workloads on a 4 GB test file inside each guest: sequential read, sequential write, random 4K read with 32 queue depth, and random 4K write with 32 queue depth. The host’s raw NVMe achieves roughly 5,800 MB/s sequential read on the same hardware as a baseline.
| Test | Host (baseline) | OrbStack | Lima | UTM (AVF) | UTM (QEMU) |
|---|---|---|---|---|---|
| Sequential read (MB/s) | 5,810 | 4,920 | 4,180 | 3,640 | 1,290 |
| Sequential write (MB/s) | 4,720 | 3,860 | 3,210 | 2,810 | 980 |
| Random 4K read IOPS (QD32) | 612,000 | 418,000 | 342,000 | 289,000 | 71,000 |
| Random 4K write IOPS (QD32) | 498,000 | 312,000 | 261,000 | 214,000 | 54,000 |
| fio mixed 70/30 (MB/s) | 3,940 | 2,880 | 2,310 | 1,940 | 620 |
| Bind-mounted host folder read (MB/s) | 5,810 | 2,140 (VirtioFS) | 1,420 (VirtioFS) | 880 (VirtioFS) | 240 (9p) |
OrbStack hits roughly 85% of host throughput for sequential reads, which is remarkable given that it is going through a virtio block device backed by a sparse disk image. Lima is close behind. UTM in Apple Virtualization mode is competitive but loses about 35% of host performance, and UTM in QEMU mode collapses to a quarter of host speed — which is expected and acceptable, because nobody chooses QEMU mode for performance, they choose it for x86_64 emulation. The bind-mount row is where many real-world workflows actually live, and it shows that OrbStack’s VirtioFS implementation is meaningfully faster than the others. If your build process touches thousands of small files on a shared host folder, this difference dominates everything else.
CPU Performance
For pure CPU work, the Apple Virtualization framework gives you very nearly bare-metal performance because the M3 cores are exposed directly to the guest with hardware virtualization extensions. The interesting question is whether one tool adds more overhead than another in the wrapping. We measured kernel compile times because they exercise the full toolchain, parallelism, and a meaningful amount of disk activity.
| Workload | Host (native macOS clang) | OrbStack | Lima | UTM (AVF) | UTM (QEMU) |
|---|---|---|---|---|---|
| Linux 6.8 kernel compile, make -j4 (seconds) | N/A (cross-compile 412 s) | 389 s | 402 s | 418 s | 1,840 s |
| FFmpeg x265 encode 90s 1080p (seconds) | 78 s | 82 s | 84 s | 87 s | 312 s |
| npm install (1.8 GB node_modules, seconds) | 61 s | 74 s | 89 s | 112 s | 340 s |
| Geekbench 6 single-core (score) | 3,108 | 3,061 | 3,042 | 3,028 | 1,420 |
| Geekbench 6 multi-core (4 vCPU, score) | 11,840 (8c) | 7,220 | 7,180 | 7,140 | 3,610 |
| Postgres pgbench, 50 clients (TPS) | 14,200 | 11,840 | 10,920 | 9,640 | 2,880 |
The takeaway is that under Apple Virtualization, all three tools are within 8% of each other for CPU-bound work, and within 4% for raw single-core score. The differences in real-world benchmarks like npm install come from the I/O subsystem and not the CPU. QEMU mode is, again, in a different league of slowness — five times slower for kernel compile — and is suitable only when you have no other option for the architecture you need.
Memory Footprint
Memory matters on a 36 GB MacBook because if you have your editor, browser, Slack, and a few VMs running, you can run out faster than you think. We measured the resident set size of the VM host process plus the guest’s own reported memory pressure under both idle and loaded conditions. “Loaded” here means a docker-compose stack with Postgres, Redis, and three Node services running plus a single page-load on each.
| State | OrbStack | Lima | UTM (AVF) | UTM (QEMU) |
|---|---|---|---|---|
| VM process idle (MB on host) | 410 | 980 | 1,820 | 2,140 |
| VM process under load (MB on host) | 3,120 | 4,680 | 6,210 | 6,840 |
| Guest reported “used” idle (MB) | 180 | 410 | 620 | 620 |
| Guest reported “used” loaded (MB) | 2,840 | 3,920 | 4,510 | 4,510 |
| Memory ballooning supported | Yes (aggressive) | Yes | Partial | No |
| Returns memory to host on idle | Yes (within seconds) | Yes (within minutes) | No | No |
OrbStack’s memory model is the closest thing to magic in this entire roundup. Where UTM allocates the full 8 GB of guest RAM up front and holds onto it until you stop the VM, OrbStack starts at a tiny footprint and grows as needed, then aggressively returns memory back to the host when the guest goes idle. On a 36 GB machine this is not life-changing, but on the 18 GB or 24 GB MacBook Air models a working developer might own, it is the difference between being able to keep a VM running all day or having to stop and restart it constantly. Lima is the middle ground — it does ballooning, but more conservatively. UTM treats memory the old-fashioned way: ask for it, get it, hold it.
Network Latency
Network performance inside a VM is usually measured wrong. People test VM-to-internet bandwidth and report a number, but for a developer the host-to-VM round trip is what matters because you are constantly hitting localhost-mapped services from your editor or browser on the host. We measured both, plus a 1 KB UDP ping for jitter.
| Measurement | OrbStack | Lima | UTM (AVF) | UTM (QEMU) |
|---|---|---|---|---|
| Host to VM TCP latency (ms, p50) | 0.18 | 0.34 | 0.41 | 0.92 |
| Host to VM TCP latency (ms, p99) | 0.41 | 0.78 | 1.10 | 3.40 |
| Host to VM throughput (Gb/s, iperf3) | 38.4 | 22.1 | 18.6 | 4.2 |
| VM to internet ping (ms vs host) | +0.2 | +0.4 | +0.6 | +1.8 |
| VM to internet download (Mbps vs host) | -1% | -2% | -3% | -15% |
| Port forwarding setup | Automatic | YAML config | GUI dialog | GUI dialog |
| Custom domain (.local DNS) | Yes (mycontainer.orb.local) | No (manual) | No | No |
The 38 Gb/s host-to-VM throughput in OrbStack reflects that it uses a vsock-based networking layer rather than going through a virtual NIC, which is fundamentally faster but less compatible with tools that expect a real network interface. For 99% of developer workloads this is invisible and great. For network-protocol research or anything that wants to put a VM on a real bridged network with its own IP on your LAN, UTM is the only tool that does this cleanly without serious effort.
Docker Performance
Docker is the workload most people on macOS actually care about, so it deserves its own section. We compared OrbStack’s built-in Docker engine, Lima with nerdctl-compatible Docker socket, UTM running Docker installed manually inside the guest, and a baseline of Docker Desktop 4.30 for context.
| Operation | OrbStack | Lima + nerdctl | UTM (manual install) | Docker Desktop 4.30 |
|---|---|---|---|---|
| Pull alpine:latest (cold cache, seconds) | 1.4 | 2.8 | 3.6 | 2.1 |
| Pull node:20 (480 MB, cold cache, seconds) | 11.2 | 14.6 | 18.4 | 16.8 |
| docker run hello-world (seconds) | 0.21 | 0.48 | 0.71 | 0.62 |
| docker-compose up (3 services, cold, seconds) | 3.8 | 6.2 | 9.1 | 7.4 |
| Build Node 20 image, no cache (seconds) | 48 | 61 | 74 | 67 |
| Build Node 20 image, with BuildKit cache (seconds) | 4.2 | 7.8 | 11.2 | 9.6 |
| Bind-mount file change to container (ms) | ~50 | ~120 | ~280 | ~340 (or fsnotify-broken) |
| Memory at idle with 0 containers (MB) | 410 | 980 | 1,820 | 2,640 |
OrbStack is consistently 1.5x to 2x faster than Docker Desktop on every measured operation, while using a sixth as much memory at idle. The bind-mount file-change latency is a particularly important number for anyone using a hot-reload dev server: 50 ms feels instant, 340 ms feels broken, and Docker Desktop has historically had outright bugs where filesystem events do not propagate at all on certain mount configurations. This is the headline reason OrbStack has been eating Docker Desktop’s lunch in the macOS developer market.
GUI vs Headless
Some workloads need a graphical desktop inside the VM — testing a Linux desktop application, debugging a browser-based issue across distributions, or simply having a familiar graphical environment for someone migrating from Linux. Other workloads want pure CLI and never want a window to appear.
| Capability | OrbStack | Lima | UTM |
|---|---|---|---|
| Headless / CLI-first | Yes (default) | Yes (default) | Optional |
| Native macOS GUI window | No (limited dashboard) | No | Yes (full) |
| SPICE / VNC display | No | Optional (vncserver) | Yes (built-in) |
| GPU passthrough / acceleration | No | No | Partial (paravirtualized GL) |
| Resolution / multi-monitor | N/A | N/A | Yes (resizable) |
| Run Windows ARM64 | No | No | Yes (with caveats) |
| Run x86_64 guest | No | No (Rosetta only for binaries inside ARM guest) | Yes (QEMU mode) |
| Run *BSD or Haiku or other niche OS | No | No | Yes |
UTM is the only tool here that takes “run any operating system in a window” seriously. OrbStack and Lima are both unapologetically headless tools designed for developers who SSH into their VMs or use them as Docker hosts. If you want to install Debian with a GNOME desktop and use it like a Linux laptop inside your Mac, UTM is your only option. The other two are not even trying to compete in that space.
Counterintuitive Findings
After thirty days, several things about this comparison surprised us, and they would have surprised the Hacker News commenters too if any of them had bothered to measure rather than argue.
The first surprise is that OrbStack’s Docker engine is meaningfully faster than Docker Desktop on the same hardware, despite Docker Desktop being the official product from the company that owns Docker. The reason is architectural: Docker Desktop runs a full Linux VM through HyperKit (with all the overhead that implies), then runs the Docker daemon inside that VM, then exposes a socket back to macOS. OrbStack collapses several layers of this stack and uses Apple’s native virtualization more aggressively, with a custom-built minimal Linux distribution instead of a stock kernel. The result is that “the Docker company’s product is the slowest way to run Docker on Mac” — which is genuinely embarrassing for Docker Inc and explains a lot of the migration we have seen in 2025-2026.
The second surprise is the size of the gap between UTM’s Apple Virtualization mode and its QEMU mode. Many users do not realize UTM has two backends and assume it is “the slow one” because of QEMU’s reputation. In reality, UTM under Apple Virtualization is within 10% of OrbStack on most metrics and is a perfectly respectable choice. Switch to QEMU mode for a non-ARM guest and you fall off a cliff — kernel compile takes 4.5x longer, disk I/O drops to a quarter, and CPU benchmarks halve. The lesson is to always check which backend UTM is using before complaining about its performance, and to pick QEMU mode only when you genuinely need x86 emulation.
The third surprise, and perhaps the most practically important, is that Lima’s complexity reputation is overblown but its productivity reputation is also overblown. Lima sells itself as the minimalist tool, but to actually use it as a Docker replacement you need to install nerdctl, configure containerd, expose the socket, and write or copy a YAML configuration. None of these steps are hard, but they are steps — and during a thirty-day evaluation we found ourselves grabbing OrbStack for casual Docker work and using Lima only when we had a specific YAML config we wanted to reproduce on someone else’s machine. The thing Lima is best at is the thing nobody talks about: declarative, version-controlled VM definitions. If you have ever wanted to commit your dev environment to git in a way that just works on every team member’s Mac, Lima YAML files are the cleanest answer in the ecosystem.
A fourth, smaller surprise was bind-mount performance under VirtioFS in OrbStack versus the others. We expected all VirtioFS implementations to perform similarly because they share the same underlying protocol. They do not. OrbStack’s bind mounts are roughly 50% faster than Lima’s and 2.4x faster than UTM’s on the same workload, suggesting OrbStack has done specific tuning work — possibly around caching, possibly around how often the kernel and userspace synchronize attribute changes. This is invisible until your build tool starts traversing thousands of files, at which point it dominates the wall-clock time.
A fifth observation, more cultural than technical: OrbStack’s “just works” polish hides how much the team has invested in the small things. The auto-generated .orb.local domains for containers, the menu-bar icon that shows real-time resource usage, the seamless bidirectional clipboard, the way containers can be reached from the host without explicit port forwarding — none of these are technically novel but the cumulative effect is that you forget you are running a VM. UTM and Lima both make you remember.
Decision Framework
The right tool depends entirely on who you are and what you do. Here are the three archetypes we see most often and what we would recommend to each.
If you are a Mac-based application or web developer whose entire life is “run docker-compose up, write code, push to git,” OrbStack is the obvious choice and the $8/month subscription is the cheapest productivity investment you will make this year. The cold-start time alone changes how you work — you stop thinking of the Linux environment as something you launch and start thinking of it as something that is always there. The free tier is enough to evaluate it for a couple of weeks; after that the paid features (Kubernetes, machine snapshots, team license sync) become genuinely useful. If you are already on Docker Desktop and have not tried OrbStack, you are leaving 50% of your performance on the table for no good reason.
If you are a designer, content creator, or someone whose VM use is occasional and exploratory — “I want to install this Linux distribution and see what it looks like” or “I need to test this Windows program” — UTM is the right answer. It is free, it has a real GUI for the guest OS, it can run x86 software through emulation, and it does not assume you are a developer. The performance trade-off in QEMU mode is acceptable for occasional use, and Apple Virtualization mode is fast enough that you will not feel limited for normal Linux desktop work. Skip the App Store version; download UTM directly from the official site and you save the $10 the App Store version costs (which exists purely to support the project, not because the App Store version has features the free version lacks).
If you are a sysadmin, platform engineer, DevOps person, or anyone who scripts their environment and cares about reproducibility above all else, Lima is your tool. The YAML-based VM definitions are checkable into git, the CLI is composable with the rest of your shell-driven workflow, and there is no proprietary layer or subscription. The trade-off is that you will spend an evening getting your first config dialed in and you will need to learn nerdctl if you want a Docker-like experience. For people who already think in terms of Ansible playbooks, Terraform modules, and Dockerfiles, Lima YAML feels native. For people who want to click a button and have a thing happen, it does not.
For the indecisive: install all three. They coexist peacefully, take essentially no disk space when not in use, and learning the shape of each will make you better at picking the right tool for any given task. We kept all three installed throughout the test period and reached for each of them at different times for different reasons.
Cost
The cost story is straightforward but worth stating clearly because it matters for businesses making procurement decisions.
| Tool | Personal use | Commercial use | Notes |
|---|---|---|---|
| UTM | Free (direct download) | Free | Optional $10 App Store version is a donation, no extra features |
| OrbStack | Free tier available | $8/user/month (paid required for commercial) | Team plan $10/user/month adds SSO, license sync |
| Lima | Free | Free | Apache 2.0 license, CNCF sandbox project |
| Docker Desktop (reference) | Free for individuals | $5-24/user/month depending on tier | Required for companies over 250 employees or $10M revenue |
OrbStack’s pricing is the only point of friction here. For an individual hobbyist, the free tier is fine. For commercial use, you must pay, and there is no escape valve like Docker’s “free under 250 employees” carve-out. The math is still favorable — $96/year per developer is rounding error compared to a developer’s salary, and if it saves even one hour per month of context-switching frustration it has paid for itself. But it is real money and procurement teams will need to approve it. UTM and Lima have no such friction; they are free for any use, forever, and that simplicity has real organizational value at large companies where any subscription requires a vendor security review.
One non-obvious cost factor: the time investment to learn each tool differs significantly. OrbStack you can be productive with in five minutes. UTM takes maybe an hour to feel comfortable with the GUI, virtual machine wizard, and shared folder configuration. Lima takes an evening if you have never used it before — you need to read enough of the YAML schema to feel confident editing configs, understand how port forwarding and mount syntax work, and figure out the nerdctl story. Multiply that by team size and the “free” tools are not as free as they look. For a ten-person team, the difference between OrbStack ($960/year) and Lima (zero dollars but ten engineer-evenings of learning, perhaps $5,000 in fully-loaded time) is not as one-sided as the sticker prices suggest.
Closing Thoughts
The Hacker News thread that prompted this benchmark spent most of its 219 points debating philosophy — should a VM be a tiny minimal thing or a full desktop, should containers and VMs be different categories, is Docker Desktop morally bankrupt for charging companies for what was free five years ago. Those are interesting conversations. They are not the conversations a working developer needs to have at 2 PM on a Tuesday when the build is broken and the deadline is Friday.
The actual question — “which of these three tools should I install on my MacBook today” — has clear answers backed by clear numbers. OrbStack for Docker work. UTM for “I need a Linux desktop in a window” or “I need x86 emulation.” Lima for reproducible declarative environments and headless Linux that you control through YAML. The Apple Virtualization framework on M3 makes all three of them fast enough that performance is no longer the bottleneck — the bottleneck is now the polish around the edges, the memory model, and the developer experience choices each tool has made about what to optimize for.
Three years ago, running Linux on a Mac meant suffering. Today it means picking which excellent tool to use. That is a remarkable change, and it is mostly attributable to Apple opening up the Virtualization framework and a small number of obsessive developers — at OrbStack, in the Lima community, and in the UTM project — actually using it well. The Mac is now a first-class Linux development platform, a sentence that would have sounded absurd in 2020 and reads as obvious in 2026.
Our test methodology, raw fio outputs, and the docker-compose stacks used in these benchmarks are available on request. If you want to reproduce these numbers on your own hardware, the M3 base model is the cheapest configuration where the results will be representative; on M3 Pro and M3 Max chips, every absolute number gets faster but the relative ordering of the three tools stays the same in our spot-check testing. The story does not change with more cores; the story changes only when Apple changes what the Virtualization framework can do, which the rumors say will happen at WWDC 2026 in a month. We will benchmark again then.




Discussion