kixctl and Incus
kixctl does not replace Incus. It runs on top of it. Incus is the virtualization fabric — the thing that actually runs your containers and virtual machines. kixctl is the control plane and application-deploy layer that drives that fabric and ships your code onto it. If you already run Incus, kixctl is what you put in front of it; if you don't, Incus is the substrate kixctl expects underneath.
What Incus is
Incus is a system-container and virtual-machine manager from the Linux Containers project — the same community and maintainers behind LXC. It runs containers through LXC and virtual machines through QEMU/KVM, exposes a single REST API for both, and clusters across many machines. It began in 2023 as a community fork of Canonical's LXD, is governed under Linux Containers, and is released under the Apache 2.0 license with no contributor licensing agreement.
The distinction that matters for kixctl is the system container. An application container — Docker being the familiar case — packages a single process and shares the host kernel to run one thing. An Incus system container behaves like a whole machine: its own init, its own filesystem, a full Linux userland, while still being lighter than a full VM. Incus runs those, and it runs real VMs when you need a separate kernel or a non-Linux guest.
What kixctl adds
Incus manages instances. It has no notion of a deploy, and no opinion about your application or its lifecycle. That is the layer kixctl provides:
- Git-push, immutable deploys. kixctl builds your application into an immutable NixOS image pinned to a commit and launches it as a new revision alongside the one already running.
- Cutover and rollback as first-class actions. Promotion is a cutover you decide to make; rollback stands the previous revision — a whole, intact image — back up and swings traffic to it.
- One control plane across clusters. kixctl manages every cluster you touch from a single dashboard, with per-application configuration it injects into deployments.
Incus is the fabric. kixctl is what turns "I have a fabric" into "I push a commit, a new revision goes live, and I can roll it back to an intact previous one."
How they fit together
kixctl drives Incus entirely through the Incus REST API. It keeps its own state — users, roles, jobs, per-app configuration — in Postgres, and it reads fleet state live from Incus at render time rather than holding a synced copy, so the dashboard cannot drift from the cluster. kixctl never touches the host directly and never runs as the host's root user; every cluster action is a structured HTTPS call to Incus. The full picture is in the architecture overview.
Deployed revisions land as Incus system containers — or VMs where you need one — on kixctl's own bridge and profile, internal by default. Exposing an application is a deliberate act, not the resting state of a freshly launched instance. See the isolation model.
Why Incus, specifically
kixctl is opinionated about its substrate on purpose. Incus earns that place for a few reasons:
- A real isolation boundary. System containers and VMs are a materially stronger line than containers sharing the host kernel — the boundary that matters when you run code you didn't write, several tenants on one fabric, or anything that has to clear a security review.
- One clean API for both containers and VMs. A single documented REST API is exactly what you build a control plane against. kixctl talks to that API over a scoped client certificate and cannot widen its own access to the fabric beyond what that credential carries — a property of how it connects, not a policy layered on afterward. See how kixctl connects to Incus.
- Community-governed and Apache-licensed. Incus is a community project with no CLA, not a single vendor's product with a governance surprise waiting in it. For infrastructure you own and intend to run for years, that matters.
What kixctl does not do
kixctl does not reimplement virtualization, networking, or storage — Incus does all of that, and kixctl calls it. If what you want is to create and manage instances by hand, the incus command-line tool and API already do that well, and you may not need kixctl at all. kixctl is for the operator who wants the immutable, git-push application layer and cross-cluster control on top of Incus — without gluing a hypervisor and a separate deploy tool together and hoping the seam holds.