JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

Monolithic, Microkernel, Hybrid

You already use the kernel every time you call open() or fork(). This rung crosses the line from using it to understanding how it is built — and the first question any kernel must answer is which of its own parts to trust with full power, and which to keep at arm's length.

One privileged blob, or many guarded servers?

By the time you reach this rung you know the boundary cold: code runs either in user mode, fenced inside its own virtual address space and unable to touch hardware directly, or in kernel mode, where it owns the machine. The kernel is the one program trusted to run in that privileged mode and hand out the machine's resources to everyone else. This guide asks a question that sits one level above all of that: the kernel is itself made of many parts — a scheduler, a memory manager, filesystems, dozens of device drivers, a network stack — so where do those parts run? All together inside the trusted blob, or split out into separate, guarded pieces? That single choice is what divides every kernel design ever shipped.

It helps to make the tension physical. Inside the kernel's one address space, every component can call every other one as an ordinary function — the filesystem reads from the disk driver with a direct call, no permission slip, no copying. That is breathtakingly fast, but it also means a single wild pointer in the most obscure driver can scribble over the scheduler's data, and the whole system dies. The opposite stance says: do not trust your own drivers. Put each one in its own user-mode process with its own address space, so a bug in the sound driver can corrupt only the sound driver. Safety goes up, but now the filesystem cannot simply call the disk driver — they live in different address spaces and must send messages, which is slower. Speed-through-shared-trust versus safety-through-isolation: that is the whole debate, and the three big designs are three different answers to it.

The monolith: everything in one trusted room

A monolithic kernel takes the first answer wholesale: the scheduler, memory manager, every filesystem, the network stack, and all device drivers are linked together into one large program that runs entirely in kernel mode, sharing one address space. Linux is the canonical example, and it is monolithic in exactly this sense — when you call read() on a file, the path from the system-call entry, through the virtual filesystem, into the specific filesystem, down to the block layer and the disk driver, is a chain of ordinary function calls inside that one room. Nothing crosses an address-space boundary on the way; nothing is copied between processes. That directness is why monolithic kernels are typically the fastest design for the common path, and why Linux runs everything from a watch to a supercomputer.

The cost is written on the other side of the coin. Because every part shares the kernel's address space, every part is equally trusted and equally dangerous. A buggy third-party driver does not crash its component — there is no insulated component to crash — it can corrupt any kernel data structure it can reach with a stray write, and the usual result is a kernel panic: the kernel detects an unrecoverable inconsistency and halts the whole machine rather than risk running on corrupted state. The driver count makes this real: the vast majority of kernel code, and the vast majority of kernel bugs, live in device drivers, and in a monolith every one of them runs with full power over everything.

The microkernel: trust as little as possible

A microkernel takes the opposite answer to its logical end. It asks: what is the minimum that truly must run in privileged kernel mode? The honest answer is small — you need address-space management, basic scheduling, and a way for processes to send messages to each other. Everything else that a monolith keeps inside — filesystems, the network stack, and crucially the device drivers — is evicted out into ordinary user-mode processes called servers. The kernel itself shrinks to a few thousand lines whose one big job is to pass messages between these servers reliably. When an application wants to read a file, it sends a message to the filesystem server, which sends a message to the disk-driver server, and the tiny kernel just shuttles those messages across the address-space walls.

The payoff is fault isolation that a monolith cannot match. If the network-stack server has a bug and crashes, it crashes alone — its address space is gone, but the kernel, the scheduler, and every other server are untouched, and a supervisor can simply restart the failed server while the system keeps running. A driver that goes haywire can corrupt only its own process, never the kernel, because the hardware's memory protection stops it at the address-space wall just as it stops any user program. This is exactly why microkernels dominate where a crash is unacceptable: aircraft, car braking controllers, and secure enclaves. The high-assurance kernel seL4 is a microkernel whose core has a machine-checked mathematical proof that it is free of whole classes of bugs — a guarantee only feasible because the trusted code is small enough to reason about completely.

So why is your laptop almost certainly not running a pure microkernel? Because that file read crossed several address-space walls, and each crossing has a price. Instead of a function call, the filesystem-to-driver hop is now inter-process communication: the kernel must switch contexts, copy or remap the message, and switch back — once per server in the chain. Early microkernels in the 1990s were notoriously slow for exactly this reason, and the great achievement of the seL4 lineage was driving the cost of a message down far enough to be competitive. The microkernel bet is that the isolation is worth the IPC tax. For most desktops and servers, history judged that the tax was too high — which is what opened the door to the compromise.

The hybrid: a pragmatic middle, and the outlier

A hybrid kernel refuses to pick a side and keeps the performance-critical servers inside kernel mode while keeping a microkernel-flavoured message-passing structure on the surface. The honest way to read the word is: it is structured loosely like a microkernel but, for speed, the parts that would have been costly user-mode servers — the filesystem and the core drivers — are pulled back into the kernel's address space so their interactions are fast function calls again, not IPC. Apple's XNU (the kernel inside macOS and iOS, built on a Mach microkernel core fused with a BSD layer) and Windows NT are the famous examples. You get some of the microkernel's structural tidiness and a place to run a few things isolated, but the bulk of the hot path stays in-kernel for the same reason the monolith does: crossing address-space walls on every disk read is too expensive.

One more design belongs on the map precisely because it inverts the question. An exokernel is a research design that asks not "how should the kernel abstract the hardware?" but "what if it barely abstracts at all?" It does almost nothing except securely multiplex the raw hardware — safely handing out disk blocks, memory pages, and CPU time — and pushes the abstractions (the very notion of a "file" or a "process") up into application-level libraries that each program links. The idea is that an application that knows its own access pattern can manage its resources better than a one-size-fits-all kernel policy. Exokernels never became mainstream, but the spirit — give applications direct, safe access to hardware and skip the kernel's general-purpose middleman — echoes loudly today in unikernels and in kernel-bypass networking, so it is worth carrying as a fourth point of the compass.

Reading the choice, and the road through this rung

Step back and the four designs line up as points on a single axis — how much do you trust your own code with full privilege? The exokernel trusts almost nothing with abstraction duty; the microkernel trusts only a tiny message-passing core; the hybrid trusts a pragmatic middle; the monolith trusts the whole kernel as one. Reading any real system means reading where its drivers run, because drivers are where bugs concentrate. Notice too that the choice is not purely technical: Linus Torvalds and Andrew Tanenbaum's famous 1992 argument over monolithic versus microkernel was as much about engineering values — performance and pragmatism versus isolation and provability — as about benchmarks. Both designs ship in billions of devices today, which is the honest verdict: there is no single winner, only different tradeoffs for different stakes.

Everything else in this rung now has a home. Because the boundary between user and kernel is the heart of all four designs, the next guide opens the machine and watches it boot — how a boot sequence hands control to the kernel — and then traces the trap and interrupt mechanism, the hardware doorway through which every crossing into the kernel actually happens. With that doorway in view, the third guide follows a single system call from your read() all the way into the kernel and back, the concrete mechanism that connects an application to whichever design sits below it.

From there the rung turns inward to the monolith's machinery, because that is what Linux gives you to read. The fourth guide dissects the scheduler and how the Completely Fair Scheduler shares the CPU; the fifth confronts the deepest problem of a shared-address-space kernel — when dozens of CPUs run kernel code at once in the same memory, how do you keep data structures from being torn apart? That is where the kernel spinlock and read-copy-update earn their keep. Carry one picture through all five: the user/kernel wall, the address-space walls inside the kernel, and the price of every crossing. That single tension — trust for speed, or isolate for safety — is the thread that ties the whole rung together.