Incus-compose v1.1 has been released

Three weeks after 1.0, here’s the next release — no big theme this time, mostly hardening plus a handful of features that came out of running this in production myself.

:small_blue_diamond: Key Changes & Features

  1. Event-Driven Architecture

    • ic-healthd now reacts to Incus lifecycle events (start/stop/shutdown/delete) instead of polling.
    • up no longer polls for health/dependency waits—uses project-scoped Incus event listeners.
  2. Port Handling

    • ports: now uses userspace proxy (default: 127.0.0.1) or kernel NAT mode (opt-in via x-incus-compose.nat: true).
    • Removed x-incus-compose.nat-proxy (replaced by plain ports:).
  3. Build Improvements

    • Cross-platform support: No longer depends on umoci (Linux-only).
    • Builder detection: Uses binary name (supports podman, docker, buildah).
    • Image caching: Built images now use the same cache path as pulled images.
  4. New Features

    • configs: Mount config files from files, inline content, or environment variables.
    • networks.{name}.aliases: Extra DNS names (CNAME) for services.
    • DNS settings: dns, dns_search, domainname now map to Incus’s OCI DNS config.
    • Auto-added registries: docker.io, ghcr.io, mcr.microsoft.com, quay.io, registry.gitlab.com, codeberg.org.
  5. CLI & Behavior

    • --external-healthd can now be set in compose.yaml via x-incus-compose.healthd.external: true.
    • up --no-deps no longer skips healthd (use --no-deps --no-healthd for old behavior).
    • Multiple compose files (-f a.yaml -f b.yaml) now each get their own .incus.yaml override.
  6. Bug Fixes

    • Fixed event-driven conflicts between ic-healthd and up.
    • Improved CI reliability (E2E tests now pass consistently).

Next Steps

  • Backup support (#45) in progress.
  • OVN network support (#15) and network ACLs (#98) in design phase.

On moving both sides to events

ic-healthd got its event-driven rewrite first, and once the client’s up wait followed onto the same Incus lifecycle event stream, the two started fighting each other. One side was sure an instance was down, the other equally sure it was up — for a while there it genuinely felt like they’d each developed a mind of their own. Tamed that step by step: backoff-aware retries around Instance is busy, healthd learning not to start an instance it doesn’t own, no starting mid-backoff-wait. Slower to land than “swap poll for events” makes it sound, but idle API load is gone now and status propagates as fast as Incus reports it, not on the next poll tick.

Update

incus-compose self-update

First install:

curl -sSfL https://raw.githubusercontent.com/lxc/incus-compose/main/install.sh | sh -s -- -b ~/.local/bin

Arch users: an incus-compose-bin and incus-compose-git (maintained by @neitsab and @jochumdev) are available.

Debian users: zabbly/incus will soon have incus-compose via it’s incus-extra package.

Docs: docs.incus-compose.org · Full changelog: CHANGELOG.md

What’s next: backup (#45) @ishaan-jindal is working on it. Also scoping real OVN network support (#15) and network ACLs — firewall rules between compose networks (#98); more once the design settles.

Thanks to @ishaan-jindal for the NAT-proxy rework, configs support, and the well-known-registry expansion this cycle, and to @code-by-tanveer for pitching in on test coverage.

Still running this in production myself — Immich, Wiki.js, LeafWiki, Gitea, Caddy, Kimai, and a DNS stack. Real-world compose files remain the most useful bug reports.

René

Repo: GitHub - lxc/incus-compose: Bring the familiar Docker Compose workflow to Incus — run compose.yaml files natively on Incus · GitHub
Releases: Releases · lxc/incus-compose · GitHub
Changelog: incus-compose/CHANGELOG.md at main · lxc/incus-compose · GitHub
Previous threads: v1.0 annoucement

4 Likes

My script to update healthd of each stack:

for i in "caddy" "dns" "gitea" "immich" "a-wiki" "kimai" "other-wiki" "oci-registry-cache"; do 
  pushd $i
  incus-compose up -d
  popd
done

For anyone interested in stats:

v1.1.0

+250 Hours on my Kimai - 572 Hours complete

a good chunk of this went into getting CI to pass reliably — the E2E suite was fine locally, first run, every time; getting the same result out of CI consistently took far longer than the feature work it was testing.

───────────────────────────────────────────────────────────────────────────────
Language            Files       Lines    Blanks  Comments       Code Complexity
───────────────────────────────────────────────────────────────────────────────
Go                     97      26,584     4,280     1,885     20,419      3,294
YAML                   75       2,712       217        98      2,397          0
Markdown               16       1,533       448         0      1,085          0
Plain Text              8          10         4         0          6          0
HTML                    7          26         0         0         26          0
Shell                   6       1,190       164        77        949        119
TOML                    3         216        70        22        124          0
Dockerfile              2          19         2         0         17          0
JSON                    1          34         0         0         34          0
License                 1         202        33         0        169          0
───────────────────────────────────────────────────────────────────────────────
Total                 216      32,526     5,218     2,082     25,226      3,413
───────────────────────────────────────────────────────────────────────────────
Processed 904072 bytes, 0.904 megabytes (SI)
───────────────────────────────────────────────────────────────────────────────

v1.0.0

~/projects/incus-compose tags/v1.0.0* ≡
❯ scc
───────────────────────────────────────────────────────────────────────────────
Language            Files       Lines    Blanks  Comments       Code Complexity
───────────────────────────────────────────────────────────────────────────────
Go                     84      23,549     3,763     1,701     18,085      3,090
YAML                   55       2,116       175        95      1,846          0
Markdown               16       1,474       450         0      1,024          0
HTML                    6          18         0         0         18          0
Dockerfile              3          30         6         0         24          0
Plain Text              3           4         0         0          4          0
Shell                   3         797        83        52        662         80
JSON                    1          34         0         0         34          0
License                 1         202        33         0        169          0
TOML                    1           2         0         0          2          0
───────────────────────────────────────────────────────────────────────────────
Total                 173      28,226     4,510     1,848     21,868      3,170
───────────────────────────────────────────────────────────────────────────────
Processed 781605 bytes, 0.782 megabytes (SI)
───────────────────────────────────────────────────────────────────────────────
1 Like

You guys are really working hard to make incus ecosystem better day by day. Thank you.

1 Like