Declarative configuration management for Incus.
Install the latest release binary:
curl -LO https://github.com/abiosoft/incus-apply/releases/latest/download/incus-apply-$(uname)-$(uname -m)
sudo install incus-apply-$(uname)-$(uname -m) /usr/local/bin/incus-applyOr build from source (requires Go):
git clone https://github.com/abiosoft/incus-apply
cd incus-apply
make && sudo make install- Create a config file
debian.yaml:
kind: instance
name: debian
image: images:debian/12
profiles:
- default
config:
limits.cpu: "2"
limits.memory: 1GiB- Apply it:
incus-apply debian.yamlUsage:
incus-apply [flags] [file...] [remote:]
Flags:
--command-timeout duration Timeout for individual incus commands (0 disables the timeout) (default 5m0s)
-d, --delete Delete resources instead of creating/updating
--diff string[="text"] Show preview only without applying (values: text, json)
--fail-fast Stop on first error instead of continuing
--fetch-timeout duration Timeout for fetching remote config URLs (0 disables the timeout) (default 30s)
--force-local Force using local unix socket
-h, --help help for incus-apply
--launch Start newly created instances after creation (default true)
--no-wait-cloud-init Skip waiting for cloud-init to complete after instance creation
--project string Incus project to use
-q, --quiet Suppress progress output
-r, --recursive Recursively find .yaml/.json files in directories
--replace Delete and recreate managed resources when create-only fields change. Without this flag, resources with create-only field changes are skipped with a warning.
--reset Delete all resources then recreate them from configs
--select Interactively select which resources to include before applying
--show-env Show actual environment config values in preview output instead of redacting them
--stop Force-stop running instances before applying updates
-v, --verbose Show verbose output: print all setup command output and log each incus command
--version version for incus-apply
-y, --yes Auto-accept and apply changes without prompting
Configuration files can be any .yaml, .yml, or .json file. When scanning a directory, incus-apply reads all YAML and JSON files and processes only the documents whose kind matches a supported incus resource type, skipping everything else.
# web-server.yaml
kind: instance
name: web-server
image: images:debian/12
profiles:
- default
config:
limits.cpu: "2"
limits.memory: 1GiB
devices:
root:
type: disk
pool: default
path: /
size: 10GiB
description: Web server containerMultiple resources can be defined in a single file using YAML document separators (---):
# stack.yaml
---
kind: profile
name: app-profile
config:
limits.memory: 512MiB
---
kind: instance
name: app-1
image: images:alpine/3.19
profiles:
- default
- app-profile
---
kind: instance
name: app-2
image: images:alpine/3.19
profiles:
- default
- app-profileDeclare variables with kind: vars and reference them with $VAR or ${VAR} in resource documents.
---
kind: vars
vars:
NODE_ENV: production
MYSQL_DATABASE: app
---
kind: instance
name: api
image: docker:node:20
config:
environment.NODE_ENV: $NODE_ENV
environment.MYSQL_DATABASE: $MYSQL_DATABASEFor full variable usage, scoping rules, and syntax, see docs/configuration-reference.md.
| Type | Description |
|---|---|
instance |
Containers and virtual machines |
profile |
Configuration profiles |
network |
Networks (bridge, ovn, macvlan, etc.) |
network-forward |
Forward external addresses and ports |
network-acl |
Network access control lists |
network-zone |
DNS zones |
storage-pool |
Storage pools |
storage-volume |
Custom storage volumes |
storage-bucket |
S3-compatible storage buckets |
project |
Projects for resource isolation |
cluster-group |
Cluster member groups |
Resources are automatically created in dependency order:
- Projects
- Storage pools
- Networks
- Network forwards
- Network ACLs
- Network zones
- Storage volumes
- Storage buckets
- Cluster groups
- Profiles
- Instances
For deletion, the order is reversed.
| Field | Type | Description |
|---|---|---|
type |
string | Required. Resource type |
name |
string | Required. Resource name |
config |
map | Resource configuration options |
devices |
map | Device configurations |
description |
string | Resource description |
For the full per-resource field reference, see docs/configuration-reference.md.
The examples directory contains ready-to-run configurations covering a range of real-world use cases:
- resources — Individual resource definitions to get started quickly: containers, VMs, OCI instances, networks, storage, profiles, projects, and more.
- incus-vm — Spin up a nested Incus environment inside a VM. Choose between an Ubuntu 24.04 variant or a Debian 13 VM with the Zabbly kernel — both use ZFS storage and are trusted by the host automatically.
- wordpress — Deploy a full WordPress stack three ways: OCI application containers, a Debian system container, or a virtual machine — all provisioned via cloud-init in a single
incus-applyrun. - incus-os — Download Incus OS iso and create an Incus OS installation.
- windows — Download Windows 11 iso and create a Windows 11 AMD64 VM installation.
# Apply all configs in current directory
incus-apply .
# Apply specific files
incus-apply instance.yaml network.yaml
# Apply recursively from a directory
incus-apply ./configs/ -r
# Apply from stdin
cat instance.yaml | incus-apply -
# Apply from URL
incus-apply https://example.com/instance.yaml
# Show diff only (no apply)
incus-apply . --diff
# Auto-accept changes without prompting
incus-apply . -y
# Silent mode for CI (no prompt, no progress output)
incus-apply . -yq
# Delete resources defined in configs
incus-apply . -d -y
# Apply to a specific project
incus-apply . --project myproject
# Apply to a specific remote server (append remote name with trailing colon)
incus-apply instance.yaml server-a:
# Apply to a specific project on a remote server
incus-apply instance.yaml --project myproject server-a:Preview, diff, and apply behavior
By default, incus-apply shows a preview and asks for confirmation before making changes.
- Use
--diffto preview only. - Use
--diff=jsonfor machine-readable output. - In non-interactive environments, use
--yesto proceed. - If planning hits errors, the preview is still shown but apply/delete stops before making changes.
- Instance
config.environment.*values are redacted in preview output by default. - Use
--show-envto reveal those values in preview output when needed.
Preview output identifies resources by effective scope:
- Resources use
type/name, for exampleinstance/web. - Pool-scoped storage resources use
project:type/pool/name, for exampledefault:storage-volume/pool1/data. - Global resources omit the project prefix and use
type/name.
Recreate-required changes
Some fields are create-only, such as an instance image, storage pool driver, or network type.
When those fields change on a managed resource, the preview is marked recreate required and apply stops before making changes.
Use --replace to delete and recreate the resource in one run.
For schema URL and editor setup, see docs/editor-schema.md.
See docs/faq.md for common questions and operational notes.
Apache 2.0
If you (or your company) are benefiting from the project and would like to support the contributors, kindly sponsor.