Incus/LXC System Containers vs Docker Application Containers

Photo by Manele R. via Wikimedia Commons (CC BY 2.0)
A system container simulates a full operating system: it runs its own init (like systemd), multiple processes, users, and persistent state, behaving like a lightweight server you log into. An application container, like Docker's, packages a single process and its dependencies as an immutable, disposable image. Both share the host kernel, but they are built for opposite lifecycles.
Incus is the community fork of LXD, created after Canonical took LXD in-house, and it is now maintained under the Linux Containers project. It manages both LXC system containers and full virtual machines from one CLI and API. The current LTS is Incus 6.0, with Incus 7.x on the feature-release track.
Yes. You enable security.nesting on the container and install Docker normally, which is a common way to get VM-style isolation plus the Docker ecosystem on one host. The reverse does not work: you cannot run Incus inside a Docker application container. Since Incus 6.3 you can also run OCI/Docker images directly in Incus without Docker at all.
Use a system container when your workload is Linux-on-Linux and you want density and fast startup: containers share one kernel and only use the memory their processes touch, so you fit far more per host than with VMs. Choose a VM when you need a different kernel version, a non-Linux guest, custom kernel modules, or hard isolation for untrusted code.
No, they solve different problems. Docker excels at packaging and shipping single stateless applications with a huge ecosystem of registries, Compose, and CI integration. Incus excels at running many persistent, isolated, full-OS environments cheaply. Many setups use both: Incus system containers for isolation, Docker inside them for the app-container workflow.

Photo by Manele R. via Wikimedia Commons (CC BY 2.0)
Key Takeaway
Incus and LXC run system containers: persistent, full-OS Linux instances with their own systemd, users, and services that share the host kernel. Docker runs application containers: one process, immutable, disposable. Use Incus when you want a lightweight VM-like box you SSH into and manage; use Docker to ship a single stateless app.
Most engineers meet containers through Docker, so they assume every container is a thin, throwaway wrapper around a single process. Then they hit a workload that wants a real machine: an init system, multiple daemons, cron jobs, users who SSH in, and state that survives reboots. You can bend Docker into that shape, but you spend the whole time fighting its design. That is where system containers earn their place, and Incus is the tool I reach for.
Incus is the community fork of LXD, now maintained under the Linux Containers project after Canonical took LXD in-house. It manages both system containers (via LXC) and full virtual machines from one CLI and API. This post is about where system containers sit between Docker and a VM, and how to pick the right one instead of reaching for Docker by reflex.
An application container packages one process and its dependencies. The Docker philosophy is one concern per container, immutable image, ephemeral runtime: you rebuild the image to change anything, and the container's writable layer is disposable. A system container instead simulates a full operating system. It boots its own init (systemd or similar), runs many processes, holds persistent state on disk, and behaves like a small server you log into. Both share the host kernel through namespaces and cgroups, so neither pays the boot time or memory tax of a real VM.
The mental model that clicked for me: Docker gives you a process wearing a container as a costume; Incus gives you a machine that happens to share a kernel. When you ask what happens on restart, the answer separates them. Restart a Docker container and the writable layer is gone unless you mounted a volume. Restart an Incus container and everything is still there, because it was never designed to be thrown away.
| Dimension | Incus / LXC system container | Docker application container |
|---|---|---|
| Unit of packaging | A full OS userland with init, many processes | A single process and its dependencies |
| Lifecycle | Persistent, pet-like: you patch and keep it | Ephemeral, cattle-like: rebuild and replace |
| State on restart | Survives by default, like a server | Writable layer lost unless a volume is mounted |
| Kernel | Shared host kernel (no separate kernel) | Shared host kernel (no separate kernel) |
| Ecosystem for shipping apps | Weaker; not built around a registry workflow | Huge: Docker Hub, Compose, CI images everywhere |
| Best fit | Multi-service boxes, dev sandboxes, VM replacement | Stateless microservices, reproducible builds |
If a system container already feels like a small server, why not just run a VM? Density and speed. A VM boots its own kernel and reserves its own RAM, so ten VMs mean ten kernels and ten fixed memory allocations. Ten system containers share one kernel and only use the memory their processes actually touch. On a modest VPS I can run far more isolated environments as containers than as VMs, and each one starts in under a second instead of tens of seconds.
The trade-off is the shared kernel. Every container runs the host's kernel, so you cannot run a different kernel version, load a custom kernel module per instance, or boot a non-Linux guest. You also lean harder on namespace isolation than on a hypervisor boundary. For most Linux-on-Linux workloads that is a fine deal, and Incus lets you launch a real VM from the same tool when a workload genuinely needs one.
Shared kernel means a kernel-level container escape reaches the host directly, with no hypervisor in between. For hard multi-tenant isolation of untrusted code, a VM boundary is still stronger. Incus 7.2 added per-instance SELinux confinement to tighten this, but do not treat a system container as equivalent to a VM for adversarial workloads.
The workflow is deliberately server-like. You launch an image, and then you treat the result like a fresh machine: shell in, install packages, run systemd services, and it all persists. Here is the minimal path from a clean Incus install to a running Debian container you can log into.
# Initialise Incus once (accept defaults for a simple setup)
incus admin init --minimal
# Launch a persistent Debian 12 system container
incus launch images:debian/12 web01
# It boots its own init and runs many processes
incus exec web01 -- ps aux
incus exec web01 -- systemctl status
# Get a real shell, install and enable a service
incus exec web01 -- bash
# apt update && apt install -y nginx
# systemctl enable --now nginx
# Restart the container: state and installed packages survive
incus restart web01
incus listSince Incus 6.3 you are not locked out of the Docker ecosystem either. Incus can pull OCI images straight from registries like Docker Hub, using skopeo and umoci to flatten them, and run them as application containers alongside your system containers and VMs. It is still young and has gaps, but for simple cases it means one tool can cover both container styles.
# Add the Docker Hub OCI remote, then run an app container from it
incus remote add docker https://docker.io --protocol=oci
incus launch docker:nginx:latest myproxy
# Docker also runs happily INSIDE a system container
# (the reverse never works: you cannot run Incus in a Docker container)
incus config set web01 security.nesting=true
incus exec web01 -- bash -c 'curl -fsSL https://get.docker.com | sh'None of this makes Docker obsolete. If you are shipping a stateless service, Docker's immutable image and huge ecosystem are exactly what you want. The whole industry speaks Dockerfile, Compose, and OCI registries; CI systems, PaaS platforms, and Kubernetes all assume application containers. For reproducible builds and stateless microservices, Docker is the path of least resistance and I still use it daily for my own services.
A pattern I like on a single VPS: use Incus system containers as clean, isolated environments (one per project or client), and run Docker Compose inside whichever container needs the app-container workflow. You get VM-style separation and the Docker ecosystem at the same time, from one host, with one manager.
The takeaway is not Incus versus Docker as rivals. They solve different problems. Docker answers how do I package and ship one application; Incus answers how do I run many isolated machines cheaply. Once you stop forcing every workload into an application container, both tools get simpler to use, and your VPS gets a lot more room to breathe.