Incus is a single daemon with a REST API that runs OCI application containers, LXC system containers, and full virtual machines side by side. It is Apache-2.0, developed in the open under the Linux Containers project by the team that started LXC in 2008.
Most compose tooling assumes a Docker-style OCI engine. incus-compose runs
your existing compose.yaml against Incus instead - we treat a compose file
that doesn't run as a bug, unless the
compatibility matrix says it doesn't.
A typical container-plus-VM setup accumulates an engine daemon, a container runtime under it, a hypervisor manager beside it, network plugins, storage drivers, and a different CLI for each. Incus ships all of it - containers and VMs, networking, storage, images, projects, clustering - as one package and one daemon.
Running an OCI engine inside an Incus container is a common workaround, and it costs something:
flowchart TB
subgraph container["Incus Container"]
subgraph engine["OCI Engine Daemon"]
app["Your App"]
end
end
Incus runs OCI images directly: the app is PID 1, with no init system and no
second engine in between. incus-compose drives that mode.
flowchart TB
subgraph incus["Incus"]
app["Your App"]
end
When an app needs a full OS environment instead, point image: at a system
container image and Incus boots it with a real init:
services:
app:
image: images:debian/trixie
| Feature | OCI Engines | Incus |
|---|---|---|
| Container type | Application (PID 1 = app) | Application (PID 1 = app) or system (full init) |
| Isolation | Namespaces + cgroups | Namespaces + cgroups, unprivileged by default |
| Security | Daemon runs as root; rootless is opt-in | AppArmor + seccomp confinement by default |
| Networking | Port mapping via iptables | Real IPs and port proxies |
| Storage | Overlay filesystem | ZFS/Btrfs with instant snapshots (pool-dependent) |
| Image caching | Per-engine cache | Global blob cache, per-project alias |
Every container gets its own network address, so two services can both listen on port 80 without a port-mapping puzzle. Shell into any container for debugging, snapshot it before a risky upgrade, roll back in seconds.
Compose files reach the rest of Incus through x-incus: project-wide resource
limits, static IPs, GPU passthrough, and storage-pool placement. See the feature
overview on the home page and the complete matrix in
Compose Compatibility.
Incus is client/server. The daemon is Linux-only, but the incus client (and
incus-compose) is a cross-platform Go binary. From a Windows or macOS desktop
you connect to a remote Linux host over HTTPS and manage OCI app containers,
system containers, and full VMs, without Docker Desktop, WSL, or a local Linux
VM.
flowchart LR
subgraph D["your desktop - Windows, macOS, or Linux"]
CLI["incus<br/>incus-compose"]
end
subgraph H["a Linux host"]
INCUSD[incusd]
INCUSD --> OCI[OCI application containers]
INCUSD --> SYS[system containers]
INCUSD --> VM[virtual machines]
end
CLI -->|HTTPS| INCUSD
Docker Desktop works differently: on Windows and macOS it runs a hidden Linux VM to host the engine, so the workload runs on your laptop rather than on the server.
See Installing on Windows for the client setup.
The API is the same on one host and on many, so there is no second orchestration layer to learn: Incus clustering covers placement and live migration across hosts, and IncusOS is an immutable OS purpose-built to run it.
Those capabilities are Incus's. incus-compose runs on single hosts and small
clusters today and has not been exercised across a hundred-node deployment.
One caveat either way: Incus's OCI application-container support is newer than its system-container support and has seen less production mileage.