Skip to main content

Command Palette

Search for a command to run...

Unikernels: Less Is More

Updated
6 min read
Unikernels:  Less Is More
I

A drive for problem solving and new technologies. Here to write about anything and everything about software development.

Imagine you had a big box of toys and whenever you wanted one of the toys (say Super Mario action figure), you’d have to take out all the toys in your toy box just to find the action figure. This is kinda how servers currently operate, they wake up unnecessary tools, modules, and processes that bog down your operational time, most of which your application never even touches.

Now imagine your action figure sitting alone in that toy box. No clutter, no digging around, nothing unnecessary. That's the idea behind Unikernels; just your app and exactly what it needs to run, nothing more.

How we got here

To truly appreciate what Unikernels bring to the table, we must first reminice on the road we've travelled.

We started with bare metal servers; powerful, but wasteful. Running one application meant an entire physical machine sitting mostly idle. Then came Virtual Machines (VMs), which let us slice one physical server into multiple isolated environments. A big win. But VMs carry a full operating system each, which means more bloat, slower boot times, and significant memory overhead.

Containers were the next leap(my favorite actually). Lighter than VMs, faster to spin up, and sharing the host OS kernel; they became the sweetheart of modern infrastructure. Docker, Kubernetes, the whole ecosystem exploded in response to this awesome new tool. But here's the thing: containers still inherit a lot of baggage from the layers beneath them, from support for old physical protocols to backward-compatible interfaces like POSIX, user-space processes, managed runtimes like .NET or Java, etc. Every few years, we add more layers onto an already heavily layered stack in the guise of innovating more. Containers made that stack more manageable, but they didn't make it thinner.

Enter Unikernels (into the Dragon)

In a world where application isolation through virtualization has been the guiding north star, Unikernels are a step in a different direction entirely; not just better isolation, but a fundamentally leaner approach to running modern software.

A Unikernel is built by taking your application's source code and combining it directly with only the OS libraries it actually needs: the specific drivers, the TCP/IP stack, whatever is necessary, and compiling all of it into a single, bootable image. That image runs directly on a hypervisor like KVM, Xen, or AWS Nitro. No host OS sitting in between. No unused modules loaded in memory. No processes your app didn't ask for.

Here's what that looks like in practice:

  • Single address space: Your application runs in the same address space as the kernel, which eliminates the performance cost of constantly switching between user space and kernel space.

  • Minimalist by design: Unikernels typically weigh just a few megabytes. Compare that to a container image that can balloon into hundreds of megabytes carrying dependencies your app might never use.

  • Immutable and single-purpose: A Unikernel is built to run one thing. That specificity is a feature, not a limitation.

The Security Angle

Think back to the toy box analogy. When it's packed full of toys, the lid barely closes, things are poking out, the box is heavy, hard to manage, and easier to get into. Now picture that same box with just your action figure inside. Lid shuts clean. Nothing spilling over. Much harder to compromise right?

That's what Unikernels do for security. The fewer components in a system, the smaller the attack surface. There's no shell to exploit, no unnecessary services listening, no legacy interfaces waiting to be poked at. Most attack vectors that work against traditional operating systems simply don't exist in a Unikernel environment. What doesn't exist can't be exploited.

Why This Matters

Unikernels aren't just a technical curiosity, they represent a meaningful shift in how we think about the relationship between software and hardware. Every layer we've added over the decades — from physical servers to VMs to containers — has been an attempt to make computing more flexible and efficient. Unikernels strip the question back to its core: what does this application actually need to run?

The answer, it turns out, is a lot less than we've been giving it.

We're one step closer to software running as close to the hardware as possible; fast, lean, secure, and purpose-built. Unikernels aren't fully mainstream yet, and like any technology they come with real tradeoffs.

The Cons

The biggest hurdle right now is debugging. Because a Unikernel runs without a traditional OS, the familiar debugging tools aren't present; no shell to SSH into, no standard logging infrastructure, no attaching a debugger the conventional way. When something goes wrong, diagnosing it is genuinely harder. Beyond debugging, the tooling ecosystem is still young. Containers have Docker, Kubernetes, and a massive community behind them while Unikernels don't have that yet. Building one requires familiarity with frameworks like MirageOS, Unikraft, or OSv, each with their own learning curve. There's also the single-purpose constraint; a Unikernel does one thing, which is great for production but also means you're building and maintaining a separate image for every application. None of these are dealbreakers, but they're real costs worth weighing before jumping in.

The technnology is still relatively new and is actively gowing a community which makes it prospective project.

Running Unikernels Locally

Now for the part you have been waitinng for. The easiest way to get a Unikernel running on your machine today is through Unikraft, one of the more developer-friendly frameworks available.

  1. First, make sure you have QEMU installed. This is the hypervisor your Unikernel will run on locally. On a Mac you can install it with brew install qemu, and on Ubuntu with sudo apt install qemu-system-x86.

  2. Next, install the Kraftkit CLI, Unikraft's build tool by running curl --proto '=https' --tlsv1.2 -sSf https://get.kraftkit.sh | sh.

  3. Once that's set up, you can pull a pre-built Unikernel image with kraft pkg pull unikraft.org/nginx:latest and run it with kraft run unikraft.org/nginx:latest.

That's it! You'll have a Unikernel-based Nginx server booted and running in milliseconds, directly on your hypervisor, no OS in between. From there you can explore building your own by writing a Kraftfile that defines your application and its required libraries, then running kraft build and kraft run to compile and launch it, pretty similar to Docker image builds and container runs.

Unikernels are quietly making their way into production environments, particularly where performance & security margins matter most. Cloudflare has leaned into unikernel-like architecture with their Workers platform, stripping down the execution environment to the bare minimum needed to run code at the edge. AWS has taken a similar philosophy with Firecracker, the microVM technology powering Lambda and Fargate although it's not a traditional Unikernel but borrows heavily from the same thinking: boot fast, carry nothing unnecessary, isolate aggressively.
Every generation of infrastructure technology has asked the same question in a different way: "how do we get applications running more efficiently, more securely, and closer to the hardware?" I believe Unikernels are a step in the right direction.