Incus vs Docker: Containers That Look Similar but Solve Different Problems
If you have been following the container conversation on this blog, you have seen it from both ends of the runtime argument. The Docker vs Podman comparison settled that the runtime matters less than who owns the process tree, and the Compose vs Kubernetes post drew the line for when a cluster earns its keep. Then the Proxmox vs IncusOS post introduced the other family: Incus, the open source manager for system containers that grew out of LXD, and the immutable IncusOS appliance built to run it.
What none of those posts did was slow down on a confusion that trips up newcomers and veterans alike: Docker runs containers, Incus runs containers, so why are they not interchangeable tools? This post is the theoretical version of that answer. The useful mental model is that the word container names a mechanism, not a goal. Docker and Incus both use that mechanism, and they wrap it in completely different abstractions, aimed at completely different problems.
The short version
- Docker containerizes applications. It packages one piece of software with its runtime into an OCI image, and a container is that application running in isolation.
- Incus containerizes systems. It launches full operating system images, complete with init, systemd, users, and package managers, and an instance behaves like a small Linux machine.
- Both are built on the same kernel primitives. Namespaces, cgroups, and layered storage are the shared foundation, which is why the two tools look so similar and why the similarity ends there.
- The unit of management is the real difference. Docker manages applications you can throw away and replace. Incus manages machines you snapshot, clone, upgrade, and keep.
- The abstractions map to different strengths. Docker wins for reproducible application delivery; Incus wins for OS-level isolation and stateful systems.
- They are complements, not rivals. Docker inside Incus is a normal pattern; the reverse is not. Choosing between them means deciding what the unit of your infrastructure actually is.
What the word container hides
Every modern container story starts in the Linux kernel. Namespaces isolate processes from each other: PID, mount, network, user, and the rest. Cgroups bound what those processes can consume. Layered storage turns a filesystem into a diffable stack of layers. Those three primitives give any tool the ability to run a process that believes it has its own machine.
What the kernel does not tell you is what should live inside that process. That decision is the product decision, and it is the whole difference between Docker and Incus.
Docker answered: one application. A Docker image is a build artifact. It contains the files your software needs, a CMD or ENTRYPOINT that tells the runtime how to start it, and almost nothing else. The abstraction becomes meaningful because you can run that image identically on a laptop, in CI, and in production. The container is the smallest deployable unit that still carries the whole application.
Incus answered: one machine. An Incus image is a snapshot of an operating system. It contains /etc, an init system, users, and a package manager. Launching an instance is closer to booting a small Linux box than to running a service, and that instance is expected to keep running, to be upgraded, to hold state, and to be snapshotted before changes. That is the system container, the LXC and LXD lineage that Incus continues under the Apache-2.0 license.
Two kinds of images, two lifecycles
Follow the image format and you see the philosophy. Docker images are assembled from layers with metadata describing how to run the software, and they are built to be immutable. You do not patch a running image; you build a new one and recreate the container. The identity of the workload is the application, so replacing the container is the normal operation, which is why the Compose and Kubernetes conversation is really about scheduling disposable units.
Incus images are closer to disks. The format carries the whole system, and the running instance is a stateful entity with an identity: hostname, filesystem, users, installed packages, network configuration. Updates happen inside the instance with its package manager. Snapshots capture state so a failed upgrade can be rolled back. Cloning an instance is copying a machine. This is the model of a hypervisor without the overhead of a second kernel, and it is the same conceptual space where the Proxmox vs IncusOS post lives.
Why they look so similar
Both use the word container. Both rely on namespaces, cgroups, and layers. Both have a daemon with a client CLI, both can pull images from remote servers, and both run on a shared kernel with a fraction of a virtual machine's overhead.
The visual surface is so alike that the obvious conclusion is that Docker and Incus are two implementations of the same thing. The evidence against it is subtle. Try to treat a Docker image as a machine and you are missing an init system, a package manager, and the whole idea of in-place upgrades. Try to treat an Incus instance as an application unit and you are carrying around an entire operating system to run one process. Both work, and both feel wrong in the other model, because each tool's assumptions are baked into the format and the lifecycle.
What each abstraction is actually good at
The abstractions are not arbitrary. They emerged from different jobs, and they are good at the jobs they were shaped for.
- Docker is for software you build and ship. It is the abstraction behind dev and prod parity, microservices, registry-based distribution, and CI pipelines. The container is the artifact, and the whole ecosystem, Compose, Kubernetes, registries, image scanners, speaks that artifact language.
- Incus is for environments you run and maintain. It shines when you want whole distributions, per-project or per-client isolation, snapshots before a risky change, and instances that stay around for years. Inside that system boundary you can still run Docker for the applications that live on it.
There is a theoretical consequence worth naming: you can usually tell which model a tool assumes by what it does when the workload misbehaves. Docker recreates the container from the image. Incus rolls back to a snapshot or reboots the instance. The failure handling exposes the intended lifetime. Application containers are designed to be replaced; system containers are designed to be repaired.
Combining them: Docker inside Incus
The two models coexist comfortably in one direction. An Incus instance gives you an isolated Linux machine, and inside it you can run Docker and use application containers for the services that live on that machine. This is a common pattern: Incus provides the system boundary, Docker provides the packaging format, and each abstraction does the job it is good at.
The reverse, running Incus inside Docker, requires nesting privileges and extra setup, and it rarely buys you anything the outer model did not already provide. The asymmetry is not an accident. A machine can contain applications; an application container was never meant to contain a machine.
The limits that bite
- Docker's model assumes the application is replaceable. State has to be pushed out to volumes and databases. A stateful application living happily inside a plain container is fighting the abstraction, which is why so many stateful workloads end up on the orchestrator's managed services instead.
- Incus instances are bigger units. Each one carries a whole operating system, which means patching and maintaining more surface. That is the price of the machine abstraction, and it is the same trade the Proxmox vs IncusOS post examines for the host operating system itself.
- System containers still share the kernel. They are not virtual machines. Kernel-level isolation is weaker than full virtualization for untrusted workloads, a boundary Incus inherits from its LXC roots and documents honestly.
- Ecosystem gravity favors Docker. Most software today publishes OCI images and expects an application container runtime. Forcing that software into system containers means extra translation layers, which is a cost you should count before you pick the more powerful abstraction.
| Feature | Incus (system container) | Docker (application container) |
|---|---|---|
| What runs in the container | A whole operating system with init, systemd, users, and a package manager | One application process tree with its runtime |
| Primary image format | OS images from the Incus and LXD ecosystem | OCI images from container registries |
| Unit of management | A machine-like instance you keep and maintain | A disposable application unit you replace |
| State | Expected; snapshots, clones, and in-place upgrades | Discouraged; state lives in volumes or external stores |
| Failure handling | Roll back to a snapshot or reboot the instance | Recreate the container from the image |
| Management model | Hypervisor-like: instances, profiles, snapshots, clustering | Orchestrator-friendly: replicas, rolling updates, scheduling |
| Lineage | LXC and LXD family | The OCI container ecosystem |
| Best for | Environments, per-client isolation, stateful systems | Application delivery, microservices, CI and CD |
What runs in the container
- Incus (system container)
- A whole operating system with init, systemd, users, and a package manager
- Docker (application container)
- One application process tree with its runtime
Primary image format
- Incus (system container)
- OS images from the Incus and LXD ecosystem
- Docker (application container)
- OCI images from container registries
Unit of management
- Incus (system container)
- A machine-like instance you keep and maintain
- Docker (application container)
- A disposable application unit you replace
State
- Incus (system container)
- Expected; snapshots, clones, and in-place upgrades
- Docker (application container)
- Discouraged; state lives in volumes or external stores
Failure handling
- Incus (system container)
- Roll back to a snapshot or reboot the instance
- Docker (application container)
- Recreate the container from the image
Management model
- Incus (system container)
- Hypervisor-like: instances, profiles, snapshots, clustering
- Docker (application container)
- Orchestrator-friendly: replicas, rolling updates, scheduling
Lineage
- Incus (system container)
- LXC and LXD family
- Docker (application container)
- The OCI container ecosystem
Best for
- Incus (system container)
- Environments, per-client isolation, stateful systems
- Docker (application container)
- Application delivery, microservices, CI and CD
Which should you pick?
- Choose Docker when the unit you reason about is an application. You build it once, you want the same artifact everywhere, and you are comfortable replacing it instead of repairing it. That is the world of the Compose and Kubernetes posts on this blog.
- Choose Incus when the unit you reason about is a machine. You want full distributions, per-project isolation, snapshots before risky changes, and instances that live for years. If the hypervisor question is already on the table, the Proxmox vs IncusOS post is the direct companion to this one.
- Use both, layered, when you want the machine boundary and the application format together. Incus for the system, Docker inside it for the software, and the two abstractions stop fighting each other.
The honest framing is architectural. Docker and Incus are not competing implementations of containers. They are different answers to the question of what a container should contain: an application or a system. Pick the abstraction that matches the unit you manage, and let the kernel mechanism do what it always did.
Official sources
- Incus documentation: https://linuxcontainers.org/incus/docs/main/
- Incus on GitHub: https://github.com/lxc/incus
- Docker documentation: https://docs.docker.com/
- Our Proxmox vs IncusOS post: https://systhoughts.com/posts/proxmox-vs-incusos
- Our Docker vs Podman post: https://systhoughts.com/posts/docker-vs-podman-self-hosted-apps
- Our Compose vs Kubernetes post: https://systhoughts.com/posts/docker-compose-vs-kubernetes-self-hosted-apps
Are you treating containers as applications or as machines, and where did the two models collide in your stack? Drop it in the comments.
Until next time, keep your systems thoughtful.

No comments yet