Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Incus vs Docker: the differences, and when to choose which

  • 10 min

By updated

Improve this page

incus logo

Incus and Docker do not do the same job. Docker runs application containers (one process, one image, disposable) to package and distribute an application. Incus runs system containers (a complete, persistent Linux distribution) and virtual machines, in the manner of a lightweight machine. This guide explains the fundamental difference, lays it out in a clear table, and says which tool to choose for which need. For anyone hesitating between the two, or coming from Docker.

What you will learn

  • The fundamental difference: application container against system container.
  • A comparison table, Incus against Docker.
  • Which tool to choose for your use case.
  • That Incus also runs Docker images (OCI).

The fundamental difference

Everything hinges on what a container holds.

A Docker container runs a single process: your application (a web server, an API, a database). The image is built in layers, the container is ephemeral (you throw it away and recreate it), and it holds only what that process strictly needs. No init, no system services, no SSH.

An Incus container runs a complete system: a Linux distribution with its init (systemd, openrc), its services, its users, its logs. It is persistent: you connect to it, administer it, snapshot it, like a small machine. That is the difference between "packaging an application" and "provisioning a machine".

Comparison table

CriterionDockerIncus
Container typeapplication (1 process)system (complete distribution)
Virtual machinesnoyes (QEMU/KVM)
Lifetimeephemeralpersistent
Imagelayered (Dockerfile)distribution (the images: remote)
Interactive accessdocker exec, logsincus shell, like a machine
Init and servicesno (1 process)yes (systemd, openrc)
Typical usedeploy an appprovision a Linux server

This first table compares the natures. To choose, you also have to compare the application workflow, because "Incus runs OCI images" does not mean it replaces the Docker toolchain. The four capabilities below are often lumped together, whereas each is decided on its own.

CapabilityDockerIncus
Run an OCI imageyes, it is its jobyes, since 6.3
Build an imageyes, Dockerfile and BuildKitno, no equivalent
Describe a multi-service setyes, Composeno, profiles and projects do not cover this need
Integrate with CI or Kubernetescomplete ecosystemnative Incus clustering, outside the Kubernetes ecosystem

Which tool to choose

The right reflex: start from the need, not from the tool.

Choose Docker (or another application engine) when you want to package and distribute an application: a microservice, a reproducible web stack, a CI/CD build. The ecosystem around it, from Docker Hub to Compose, is cut out for that.

Choose Incus when you want a Linux machine: a test server, a complete development environment, a homelab, a virtual machine for another kernel or for Windows. You manage the instance as a system, with snapshots and an API, without the weight of a full hypervisor such as Proxmox (in French).

Incus also runs Docker images

The boundary is not sealed: since version 6.3, Incus can run OCI images (Docker's format) alongside its system containers. No OCI remote is preconfigured, so you add one first:

Terminal window
incus remote add docker https://docker.io --protocol=oci
incus launch docker:nginx web

The image starts as an application container, marked CONTAINER (APP) in incus list, with its own IP address on incusbr0. An incus exec web -- nginx -v answers there as in any other Incus instance.

One check is needed before trying: OCI support dates from 6.3, so from the feature branch. Debian 13 ships Incus 6.0.4, the LTS branch, which predates it. On a standard Debian install, incus --version answers 6.0.4 and the command above cannot work: you have to move to the upstream repository.

Once that condition is met, you run application workloads without installing Docker, on the same platform as your system containers and your virtual machines. Details in running OCI containers with Incus.

Docker and Incus on the same host: does the network really break?

This is the most quoted trap, and it is conditional, not automatic. The Docker daemon can set the policy of the FORWARD chain to DROP, which stops the host from routing: Incus containers then get an IP on incusbr0 with no way out. But Docker only does so in a precise case, and Incus now protects itself against it.

Docker only sets this policy when it turns on IP forwarding itself. If it finds net.ipv4.ip_forward already at 1, it leaves it alone. Incus turns that setting on at initialisation: on a machine where Incus is installed before Docker, the chain stays at ACCEPT and the problem never shows up. This behaviour also concerns the iptables backend, still the default; the nftables backend introduced in Docker 29.0.0, experimental and to be enabled explicitly, does not turn on IP forwarding by itself.

And even under policy DROP, a recent Incus container keeps its network. Incus writes its own ACCEPT rules for incusbr0 into the FORWARD chain, and they survive a restart of the Docker daemon. The historical fix through DOCKER-USER then becomes useless. It remains useful on older versions of Incus or LXD, which did not set these rules: that is where the advice comes from.

The diagnosis, before any fix

Three commands are enough to know whether you are in the case described, and they avoid changing a firewall for nothing:

Terminal window
iptables -L FORWARD -n | head -1 # la politique : ACCEPT ou DROP
docker info --format '{{.FirewallBackend}}' # iptables ou nftables
sysctl net.ipv4.ip_forward # 1 si quelqu'un l'a déjà activé

If the policy is ACCEPT, there is nothing to fix. If it is DROP, first check that your containers really lose the network with an incus exec <name> -- ping -c 2 9.9.9.9: the presence of the DROP is not enough to conclude, since Incus's rules can let the traffic through.

The fixes, from the cleanest to the most radical

If the blocking is confirmed, the Docker configuration is the cleanest lever: "ip-forward-no-drop": true in /etc/docker/daemon.json asks it not to touch the policy. The rule-based fix, on Incus versions that set none, explicitly allows the bridge:

Terminal window
iptables -I DOCKER-USER -i incusbr0 -j ACCEPT
iptables -I DOCKER-USER -o incusbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Separation remains the most durable answer: running one inside an instance of the other removes the question of the shared firewall.

Can Incus replace Docker

Partly. For a homelab or a development workstation, running your few application services as OCI images inside Incus avoids installing Docker as well, and everything is managed in one place. For intensive application work, though (building images from a Dockerfile, multi-service Compose, Kubernetes integration), the Docker ecosystem stays more complete and better tooled. Incus complements Docker more than it fully replaces it.

Key points

  • Docker means application containers (one process, ephemeral) to package an application.
  • Incus means system containers (a complete, persistent distribution) and virtual machines, to provision machines.
  • You choose on the need: package an app (Docker) or provision a machine (Incus).
  • Since 6.3, Incus also launches OCI images (docker:), marked CONTAINER (APP); the LTS 6.0 branch of Debian 13 does not support them.
  • The two are often complementary, not competitors.

FAQ: common questions about Incus vs Docker

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn