MicroVMs vs containers vs VMs vs binaries vs bare metal

There is no best way to run software, only trade-offs between isolation, start time, memory, cost and compatibility. This page compares eight common ways to run a workload, for developers, vibe coders, AI-agent builders and CI/CD engineers.

Short answer

  • Trusted code on a machine you control: plain processes or containers.
  • Untrusted code or many short-lived isolated environments: microVMs.
  • Single-purpose services that idle most of the time: unikernel-based microVMs.
  • Rare, event-driven code: serverless functions. Tiny sandboxed plug-ins: WebAssembly.
  • Durable state, mixed operating systems: virtual machines. Full hardware, GPUs: bare metal.

Ratings below are qualitative. Where a figure is given it is a typical range that is well established in general, not a benchmark, and it varies with hardware, image size, runtime and configuration. Measured figures for MicroSaaS.app are in Where MicroSaaS.app fits and on the methodology page.

What is each way of running software?

Bare metal

Your software runs directly on a physical server with no virtualisation layer. You own the whole machine, its kernel and its hardware.

Benefits

  • Full access to every CPU feature, device and GPU.
  • No virtualisation overhead and no neighbours competing for the machine.
  • The simplest security model when the machine is yours alone.

Disadvantages

  • Slow to provision, usually minutes to days, and you pay for the whole machine whether you use it or not.
  • You patch the operating system, firmware and hardware yourself.
  • Poor density: one failure domain per box, and little isolation inside it unless you add another layer.

When to pick it. Pick it for GPU training, latency-critical or hardware-bound work, large steady databases and anything that needs the full machine.

Traditional virtual machines

A hypervisor splits a physical host into virtual machines, each with its own full operating system and virtual hardware. The boundary between guests is enforced by hardware virtualisation.

Benefits

  • Strong isolation and a familiar model: any operating system, any software.
  • Persistent virtual disks, snapshots and live migration on most platforms.
  • Mature tooling for backup, networking and compliance.

Disadvantages

  • Each guest carries a full operating system, so idle memory and boot time are high.
  • You patch every guest operating system.
  • Poor fit for short-lived or scale-to-zero work.

When to pick it. Pick it for long-lived services, mixed operating systems, lift-and-shift of existing software and workloads where isolation and persistence matter more than start time.

Containers

A container packages a program and its libraries and runs it as an isolated process on the host kernel, separated by namespaces and resource limits. It starts fast and packs densely because nothing boots a separate kernel.

Benefits

  • Fast start and high density on one host.
  • A huge ecosystem of images, registries and orchestrators.
  • Same image from laptop to production.

Disadvantages

  • All containers on a host share one kernel, so a kernel bug can cross the boundary.
  • Image pulls and orchestrator overhead dominate cold starts.
  • Container isolation alone is a weak fit for untrusted code.

When to pick it. Pick it for your own trusted services, CI jobs, and anything where a shared kernel is acceptable and an ecosystem of tooling matters.

MicroVMs

A microVM is a virtual machine stripped to the minimum: a small guest kernel, few virtual devices and no legacy hardware. It keeps the hardware isolation of a virtual machine while booting far faster and using far less memory.

Benefits

  • Hardware-level isolation with a small attack surface.
  • Boots in a fraction of a second, so scale to zero and wake on request are practical.
  • Runs a normal Linux guest, so most software runs unchanged.

Disadvantages

  • Fewer devices than a full virtual machine, and usually no GPU.
  • Self-hosting needs real engineering: images, networking and a scheduler.
  • Each instance still carries a guest kernel, so memory overhead is above a container.

When to pick it. Pick it when you run untrusted or multi-tenant code, or need many short-lived isolated environments, and a shared kernel is not acceptable.

Unikernel-based microVMs

A unikernel links your application with only the operating-system pieces it needs into one small image that runs as a single-purpose microVM. There is no shell, no user accounts and no general-purpose userland.

Benefits

  • Smallest guest: very low idle memory and boot times that can be a few milliseconds.
  • Very small attack surface inside the guest, with hardware isolation outside it.
  • Very high density and a good match for scale to zero.

Disadvantages

  • Not every program runs. Software that needs fork, many processes or unusual kernel features may need changes or may not run at all.
  • Harder to debug: no shell and limited tooling inside the guest.
  • A younger ecosystem with fewer ready-made images.

When to pick it. Pick it for single-purpose network services, such as a database, proxy or queue, that start often, idle most of the time and need strong isolation.

Plain binaries and processes (systemd)

You copy a binary onto a machine and let the init system, usually systemd, start and supervise it. All processes share the host operating system, with isolation limited to users, permissions and optional sandboxing options.

Benefits

  • The lowest overhead and the simplest thing that can work.
  • Everything is visible with standard tools: logs, top, strace, a shell.
  • Cheapest at small scale, since one machine can run many services.

Disadvantages

  • Weak isolation: a compromised process threatens the whole host.
  • Dependency conflicts and manual deployment unless you add tooling.
  • No scale to zero beyond what socket activation gives you, and the host is always on.

When to pick it. Pick it for a few trusted services on a machine you control, internal tools, and anything where simplicity beats isolation.

Serverless functions

You upload a function and the provider runs it on demand, scaling copies up and down with requests, including to zero. You do not manage servers, but you accept the provider's runtime, time limits and packaging rules.

Benefits

  • No servers to run, and a natural fit for spiky or rare traffic.
  • Scale to zero and per-invocation billing are built in.
  • Low operational effort for small event-driven code.

Disadvantages

  • Stateless by design, so state lives in other services.
  • Cold starts vary with runtime and package size, and limits on duration, memory and system access apply.
  • Hard to debug locally, and tied to the provider's model, which makes moving harder.

When to pick it. Pick it for event handlers, webhooks, glue code and APIs with irregular traffic, where you want to run nothing yourself.

WebAssembly runtimes

A WebAssembly runtime executes portable compiled modules inside a memory-safe sandbox in the host process. Modules get only the capabilities the host explicitly grants.

Benefits

  • Very fast start, often well under a millisecond to a few milliseconds, and tiny memory use.
  • One portable binary across operating systems and CPU architectures.
  • Fine-grained, capability-based permissions.

Disadvantages

  • Limited system access and threading, networking and file APIs depend on the host runtime.
  • Language and library support varies, and many existing programs need porting.
  • Security rests on the runtime being correct, and the tooling is younger.

When to pick it. Pick it for plugins, extension points, edge functions and untrusted snippets that must start instantly and run inside another program.

How do they compare side by side?

On a narrow screen, scroll the table sideways inside its frame. The first column stays in view.

Comparison of eight ways to run software across thirteen criteria
CriterionBare metalVirtual machineContainerMicroVMUnikernel microVMProcess on a shared hostServerless functionWebAssembly runtime
Isolation strengthStrongest when the machine is yours aloneStrong: hardware virtualisation boundaryModerate: namespaces on a shared kernelStrong: hardware virtualisation, minimal devicesStrong: hardware boundary plus a tiny guestWeak: users and permissions onlyDepends on the provider, often container or microVM basedStrong in-process sandbox, but relies on the runtime being correct
Cold startMinutes or longer to provisionTypically seconds to a few minutesTypically under a second to a few seconds; image pulls add timeTypically well under a secondTypically milliseconds to tens of millisecondsMilliseconds once installed; usually always onTypically under 100 ms to over a second, varies by runtime and trafficTypically microseconds to milliseconds
Idle memory overheadA whole operating system: hundreds of MB or moreA guest operating system: typically hundreds of MB to over 1 GBLow: megabytes beyond the program itselfGuest kernel plus program: typically tens of MB, with a few MB of monitor overheadLowest of the virtual machines: a few to tens of MBLowest: the program onlyNone for you while scaled to zero; provider-managedLow: megabytes
Density (instances per host)One workload per machineTens to low hundreds per host, limited by memoryHundreds or moreHundreds or more, limited by memoryMany more than a typical virtual machine, limited by memoryAs many as the operating system can scheduleProvider's concern; not your choiceThousands
Cost at small scaleHighest: you pay for the whole machineModerate: minimum instance size appliesLow on a shared hostLow when idle instances scale to zeroLow when idle instances scale to zeroLowest: one cheap machine runs manyVery low at low traffic, rises with sustained loadLow
Scale-to-zero friendlinessPoorPoorPossible with an orchestrator; cold starts cost secondsGoodExcellentNot applicable; the host stays onNativeGood
Persistence and stateFull local disksPersistent virtual disks and snapshotsEphemeral layer; volumes for stateDepends on setup; volumes can be attachedSmall volume or none; usually disposableThe host filesystemStateless; state lives elsewhereStateless by default; host-provided storage
Hardware or kernel feature accessEverything, including GPUsWhat the hypervisor exposes; GPU passthrough possibleHost kernel features; devices can be passed inLimited device set; usually no GPUOnly what the unikernel implements; no GPUEverything on the hostVery limitedOnly what the host runtime grants
Portability and compatibility (what runs unchanged)Anything built for that hardwareAny operating system image for the architectureLinux userland imagesMost Linux softwarePrograms the compatibility layer supports; fork-heavy software may not runSoftware built for that distribution and architectureSupported language runtimes within limitsModules compiled to WebAssembly; many programs need porting
Operational complexityHighestHigh: every guest to patchModerate, more with an orchestratorModerate to high self-hosted; low as a managed serviceHigh to build yourself; low as a managed serviceLow on one hostLow to run, harder to test and debugModerate; younger ecosystem
Attack surface and shared-kernel riskThe full operating systemHypervisor plus guest operating systemShared host kernel is the main riskSmall hypervisor and device modelSmallest guest, hardware isolation outsideEverything shared with the hostManaged by the providerRuntime bugs; a sandbox escape needs a runtime flaw
DebuggabilityBest: everything availableGood: shell and full toolsGood: exec, logs, standard toolsGood with a full Linux guestHarder: no shell, limited toolsBest: standard host toolsHard: logs, differing local emulationImproving; fewer tools
Best-fit workloadsGPU, latency-critical, large steady databasesLong-lived services, mixed operating systemsTrusted services, CI jobs, general appsUntrusted code, multi-tenant, short-lived environmentsSingle-purpose network services that idle most of the timeA few trusted services on one machineEvent handlers, webhooks, spiky APIsPlugins, edge functions, embedded untrusted logic

Where MicroSaaS.app fits

MicroSaaS.app runs each service in the unikernel-based microVM category. This is what we do and have measured, and where it stops.

What we do

Where it stops

Create services with the command line tool, the REST API or the MCP server. The docs show how, and CI testing and AI agents are the common starting points.

Which should I choose for my situation?

Which runtime to choose by situation
SituationPickWhy
A throwaway dependency for a CI run, such as a bucket, database or mail inboxUnikernel-based microVM or a containerIt must start quickly, cost almost nothing and disappear. A container is fine if the job is trusted; a microVM service avoids running it yourself.
A sandbox for an AI agent that runs generated code or creates its own infrastructureMicroVMGenerated code is untrusted, so hardware isolation matters more than the last bit of density.
A long-lived production databaseVirtual machine or bare metalDurable disks, predictable performance and backups matter more than start time. Disposable services are the wrong place for data you cannot lose.
GPU training or inferenceBare metal, or a virtual machine with GPU passthroughNeeds direct device access. MicroVM and unikernel services here have no GPU.
Running untrusted code from other peopleMicroVM, or a WebAssembly runtime for small plug-in logicA shared kernel is the risk. Use a hardware boundary, or a memory-safe sandbox with narrowly granted capabilities.
A latency-critical library running inside your own processPlain process or bare metal; WebAssembly if you need a sandboxCrossing a virtual machine or container boundary adds cost you cannot afford on the hot path.
A webhook handler with rare, irregular trafficServerless functionNothing to run and no cost while idle. Accept the provider's limits and cold starts.
A few trusted internal services on one boxPlain processes under systemd, or containersThe simplest thing that works. Add isolation only when the threat model asks for it.

Questions about runtimes

What is the difference between a microVM and a container?

A container shares the host kernel; a microVM boots its own small kernel behind a hardware virtualisation boundary. That makes microVMs a stronger boundary for untrusted code, at the cost of a little more memory per instance and fewer devices.

Are microVMs slower than containers?

They typically start somewhat slower and use more memory, but both are fast enough for most uses. Containers usually start in under a second to a few seconds once the image is present. MicroVMs typically boot in well under a second, and unikernel-based microVMs can boot in milliseconds. Figures vary with the image, host and runtime.

What is a unikernel?

A unikernel is an application linked with only the operating-system code it needs, run as a single-purpose virtual machine. It has no shell and no general userland, which keeps it small and fast to start, and limits what software can run on it.

When should I use bare metal instead of a microVM?

Use bare metal when you need the whole machine. That means GPUs, direct hardware access, very large steady workloads and latency that cannot tolerate any virtualisation layer.

Can WebAssembly replace containers?

Not in general. WebAssembly suits small, fast, sandboxed modules such as plugins and edge functions. Many existing programs depend on system features that a WebAssembly runtime does not provide, so they need porting.

Is a container enough to run untrusted code?

Usually not on its own. Containers share the host kernel, so a kernel flaw can cross the boundary. For untrusted code, add a hardware boundary such as a microVM or a sandboxed runtime.

Which option is cheapest at small scale?

Plain processes on one machine are cheapest, then containers, then services that scale to zero. Serverless functions and scale-to-zero microVMs cost almost nothing while idle but can cost more under sustained load. Bare metal and virtual machines cost the same whether used or not.

Do services on MicroSaaS.app run in containers?

No. Each service runs in its own microVM. Services boot in milliseconds, idle down to zero and wake on traffic. Services of different accounts share a private network, so each service's own credentials are what separate accounts.

Related: microVM and scale to zero in the glossary.

Last updated