Skip to main content

Configuration

The Avocado config defines your project from board support to provisioning, and everything in between.

Precedence of supplied values​

The Avocado CLI can be configured three ways, from highest to lowest precedence:

  1. CLI arguments
  2. Environment variables
  3. Configuration files

Configuration files​

The Avocado CLI uses a single configuration file to define your project settings, build configurations, dependencies, and provisioning profiles.

By default, the CLI looks for a configuration file named avocado.yaml in the current working directory. This can be configured to use a different file name or location.

For detailed information about all available configuration options, see the config schema.

avocado init writes a starter avocado.yaml on distro.release: 2026 and distro.channel: edge. Its first line is a yaml-language-server comment that points editors at the JSON Schema, so they validate the file as you type. avocado config schema prints the schema the installed CLI uses.

Checking your config​

The CLI warns about any key it ignores, whether it's misspelled, in the wrong place, or an old name that was renamed (extentions:). It suggests the closest valid key when one is near:

[WARNING] ./avocado.yaml: unknown key 'runtimes.dev.extentions' is ignored; did you mean 'extensions'?

These warnings go to stderr and never fail a command, so a file that built before still builds. avocado config show --output json includes them in a warnings array.

To check a config without building, run avocado config validate: YAML errors, schema violations and the CLI's own checks are errors (exit status 1), and ignored keys are warnings. It reads stdin with -c -, and --output json prints {ok, errors, warnings}.

The same schema powers editor support. Projects created with avocado init start with the yaml-language-server line, which gives VS Code (with the Red Hat YAML extension) and other YAML-language-server editors autocomplete, hover docs and validation. Add it to the top of an existing avocado.yaml to get the same:

# yaml-language-server: $schema=https://docs.peridio.com/schemas/avocado-config.json

Environment variables​

Environment variables take precedence over configuration file values. When set, they override the corresponding config field.

Environment variableConfig equivalentDescription
AVOCADO_TARGETdefault_targetTarget architecture for builds and deployments.
AVOCADO_TARGET_BOARDdefault_target_boardBoard variant within the target, feeding {{ avocado.target.board }} interpolation.
AVOCADO_RUNTIMEdefault_runtimeDefault runtime for commands that scope by runtime. Overrides default_runtime from config.
AVOCADO_REPO_URLdistro.repo.urlPackage repository URL.
AVOCADO_RELEASEVERdistro.repo.releaseverDNF releasever override (e.g., 2024/edge).
AVOCADO_DISTRO_RELEASEdistro.releaseDistribution feed year (e.g., 2024).
AVOCADO_DISTRO_CHANNELdistro.channelDistribution stability channel (e.g., edge, stable).
AVOCADO_REPO_CAdistro.repo.caPath to a CA certificate bundle that the package feed's TLS certificate is checked against.
AVOCADO_REPO_INSECUREdistro.repo.tls_verifySet to 1, true or yes to skip TLS verification of the package feed. Testing only.
AVOCADO_PARALLEL_TASKSnoneHow many tasks run at once across the install DAG, the build DAG and the SDK phase. Defaults to min(cpus, 4), and to 1 under --runs-on.
AVOCADO_NO_SESSION_CONTAINERnoneSet to 1 to run each install and build step in its own docker run instead of reusing one SDK container per command. For debugging a container an earlier step left in a bad state.

Legacy environment variables​

The following environment variables are deprecated but still supported as fallbacks:

Legacy variableReplacement
AVOCADO_SDK_REPO_URLAVOCADO_REPO_URL
AVOCADO_SDK_REPO_RELEASEAVOCADO_RELEASEVER

These two are removed, not deprecated — they are no longer read at all:

Removed variableReplacement
AVOCADO_FIT_KEY_DIRruntimes.<name>.signing.fit_key
AVOCADO_FIT_UNSIGNEDruntimes.<name>.signing.fit_unsigned

Default runtime​

Set default_runtime to avoid passing --runtime on every invocation. Resolution order from highest to lowest precedence:

  1. CLI -r/--runtime argument
  2. AVOCADO_RUNTIME environment variable
  3. default_runtime config value
  4. Auto-resolved sole runtime (when exactly one runtime is defined)
default_runtime: dev

runtimes:
dev:
# ...
prod:
# ...

When default_runtime is set, the CLI validates at startup that it references a runtime defined in runtimes:.

Default target and board​

Set default_target to avoid passing --target (-t) on every invocation. avocado init --target <target> writes it for you:

default_target: qemux86-64

Some targets are a System-on-Module (SoM) that ships on more than one carrier board. For those, the target alone is not enough — you must also set a board so the build knows which board's device tree and provisioning to use. The board feeds the {{ avocado.target.board }} interpolation and resolves from highest to lowest precedence:

  1. --target-board CLI flag
  2. AVOCADO_TARGET_BOARD environment variable
  3. The resolved runtime's target_board (when set on that runtime)
  4. Top-level default_target_board
  5. Falls back to the resolved target when none of the above are set

The --target-board flag is available on build, install, provision, runtime build, runtime provision, sdk install, ext build, rootfs install and initramfs install.

Set both keys at the top of your avocado.yaml:

default_target: 'imx8mp-var-dart'
default_target_board: 'variscite-sonata'

Or scope the board to a single runtime, which wins over the top-level default when that runtime is selected:

default_target: 'imx8mp-var-dart'

runtimes:
dev:
target_board: 'variscite-sonata'

To override per command without editing config:

avocado build --target imx8mp-var-dart --target-board variscite-sonata

The per-target Get Started page and the target's hardware page call out when a board is required and which value to use.

Add-on feeds​

distro.feeds lists the package feeds to enable, in dnf priority order (first wins). The distro feed comes first unless you list it. A name that repos: does not define names an add-on feed that the distro feed publishes for your target, such as ROS 2:

distro:
release: 2026
channel: edge
feeds:
- ros2-jazzy

An add-on needs no URL. It enables two repos off the distro feed's base URL, releasever and TLS settings: target/<target>-<name> for target installs and the SDK's target sysroot, and sdk/<target>-<name> for the SDK host. Before anything is written to avocado.lock, the CLI checks the name against the add-ons the channel publishes for the target (and, when the lock pins a feed snapshot, against that snapshot) and refuses one the target does not have, suggesting the nearest published name.

Connect configuration​

The connect section stores defaults for Avocado Connect platform commands, so you don't need to pass --org and --project on every invocation. This section is typically populated by running avocado connect init.

connect:
org: my-org-id
project: my-project-id
server_key: <hex-encoded TUF public key>
FieldDescription
orgDefault organization ID for avocado connect commands
projectDefault project ID for avocado connect commands
server_keyConnect server's TUF signing public key (hex). Per-runtime signing.server_key overrides this

Runtime signing configuration​

The per-runtime signing section names keys from the machine-local signing-key registry (avocado signing-keys). Only names appear in avocado.yaml; no key material is ever committed.

runtimes:
prod:
signing:
key: product-tuf # TUF metadata signing
fit_key: product-fit # boot FIT signing
fit_key_in_bootloader: true # default when fit_key is set
FieldDefaultDescription
keySigning key for the runtime's TUF metadata. Required for Level 2 (user-controlled root)
content_keykeySeparate key for delegated-targets metadata only
checksum_algorithmsha256sha256 or blake3
server_keyConnect server's TUF signing public key (hex); overrides connect.server_key
fit_keyRSA PEM key that signs this runtime's boot FIT. A verity rootfs needs this or fit_unsigned, since the root hash rides in the FIT
fit_unsignedfalseBuild the boot FIT unsigned. Mutually exclusive with fit_key
fit_key_in_bootloadertrue when fit_key is setAlso re-pack the feed's bootloader so U-Boot enforces fit_key. Set false to keep the distro bootloader

fit_key replaces the AVOCADO_FIT_KEY_DIR environment variable and fit_unsigned replaces AVOCADO_FIT_UNSIGNED; neither variable is read any more. See Boot signing.

One entry or named entries​

rootfs, initramfs, kernel and permissions each take either one configuration or a map of named ones. The CLI decides by the keys it finds:

  • If any key is one of that section's fields (such as packages in rootfs, or users in permissions), the whole section is one configuration, named default. A target-<name>: key next to the fields doesn't count as an entry name, so a per-target override block keeps the one-configuration form.
  • Otherwise every key is an entry name, and each entry is a configuration.

Mixing field keys with entry names is an error: permissions: is one block, because it sets a field, so 'prod' cannot be named entries. Use one form.

# One configuration: `users` is a permissions field
permissions:
users:
root:
password: ''

# Named entries: `dev` and `prod` are not permissions fields
permissions:
dev:
users:
root:
password: ''
prod:
users:
admin:
password: '$6$...'

Watch for misspellings here. permissions: { user: ... } has no permissions field, so it is read as an entry named user, not as users. The CLI warns about this: 'permissions.user' sets no permissions fields, so it is read as a named permissions entry; did you mean the field 'users'?

Named entries are referenced by name, for example permissions: prod on a rootfs, or kernel: yocto-6-6 on a runtime. For rootfs and initramfs, only the entry named default (or the only entry) is built, and overlay, post_install, image and source are read only in the one-configuration form, so use that form for images.

Rootfs configuration​

The rootfs section configures the shared rootfs sysroot used by runtime builds.

rootfs:
filesystem: erofs-lz4 # default
overlay: overlays/rootfs # optional: copied into the sysroot after package install
permissions: dev # a profile from the top-level permissions section
packages:
avocado-pkg-rootfs: '*'
FieldDefaultDescription
packagesavocado-pkg-rootfsMap of package names to version constraints. When no packages are set, the rootfs installs avocado-pkg-rootfs
filesystemerofs-lz4Image format: erofs-lz4 or erofs-zst
overlayPath or object. See Overlay below
permissionsUsers and groups for the image: the name of a permissions profile, or an inline profile
post_installScript, relative to src_dir, run on the image work directory just before the filesystem is created. It replaces the built-in steps (usrmerge symlinks, removing /media, /mnt, /srv and the contents of /boot, an empty /etc/machine-id, systemd presets, ldconfig)
imageImage wrapper options. See Image options below
source{ type: path, path: <dir> } reads the whole section from <dir>/avocado.yaml (or avocado.yml) instead, with <dir> relative to src_dir

A target-<name>: block inside rootfs overrides settings for that target, but only post_install and image are taken from it.

Initramfs configuration​

The initramfs section configures the initramfs sysroot used for the early boot environment. It takes the same fields as rootfs: overlay, permissions, post_install, source and target-<name>: blocks work the same way. These differ:

initramfs:
filesystem: cpio.zst # default
overlay: overlays/initramfs # optional: copied into the sysroot after package install
permissions: dev
packages:
avocado-pkg-initramfs: '*'
FieldDefaultDescription
packagesavocado-pkg-initramfsMap of package names to version constraints. When no packages are set, the initramfs installs avocado-pkg-initramfs
filesystemcpio.zstImage format: cpio, cpio.zst, cpio.lz4, or cpio.gz
imageWrapper options (type, args only). See Image options below

Image options​

The image block is accepted on rootfs, on initramfs, and on each extension. It configures how the produced filesystem image is wrapped and protected.

Not every field applies everywhere. type and args are read for all three. verity is read for rootfs and for extensions only; the initramfs build does not consult it.

rootfs:
image:
verity: true

extensions:
my-ext:
image:
type: kab # "kab" wraps the image with kabtool; absent or "raw" keeps the raw artifact
args: '-b -t kos.layer.basefs'
verity: true
FieldDefaultDescription
typerawkab wraps the produced image with kabtool; raw (or absent) keeps the raw artifact
argsExtra arguments passed to kabtool when type: kab
verityfalseProduce a dm-verity hash tree and root hash for this image. Read for rootfs and extensions only; the initramfs build does not consult it — see Filesystem verity

verity is a strict boolean: "true", 1 and yes are rejected rather than coerced, because a security opt-in should not be decided by a value that only looks true.

Overlay​

The overlay field on rootfs and initramfs merges a source directory from your project into the sysroot after package installation. Two forms are supported:

# Short form — merge mode (keeps the overlay files' modes)
rootfs:
overlay: overlays/rootfs

# Long form — explicit mode
initramfs:
overlay:
dir: overlays/initramfs
mode: opaque # new files get default modes and fresh timestamps
FieldDefaultDescription
diroverlayPath relative to project root (src_dir)
modemergemerge keeps each overlay file's mode; opaque applies the default (umask-filtered) mode and a fresh timestamp
preprocessfalseRun {{ }} interpolation over overlay files: true for all UTF-8 files, or a list of globs

The string short form is equivalent to { dir: "...", mode: "merge" }. The overlay path is resolved as /opt/src/<path> inside the SDK container. Overlay config participates in the sysroot stamp, so changes trigger a reinstall.

In both modes the overlay is copied over the sysroot. Paths the overlay creates are owned by root; directories that already exist keep their mode and owner, and nothing else in the sysroot is touched. Each install records the files the overlay placed and, on the next install, removes the ones the overlay no longer has (printing Removed /<path>); a path a package owns is kept, with a notice. An overlay directory that would replace a symlink or file in the sysroot fails the install.

Permissions​

The permissions section defines the users and groups baked into an image's /etc/passwd, /etc/shadow and /etc/group at build time. A rootfs or initramfs picks a profile through its permissions field, by name or inline. Projects created with avocado init start with a dev profile:

rootfs:
permissions: dev

initramfs:
permissions: dev

permissions:
dev: # NOT FOR PRODUCTION: empty root password
users:
root:
password: ''
prod:
users:
admin:
password: '$6$...' # a crypt hash, as written to /etc/shadow
shell: /bin/sh
groups: [admin, wheel]
groups:
admin:
gid: 1000

Groups are created before users, so a user can name a group defined in the same profile.

User fields​

FieldDescription
passwordPassword hash written to /etc/shadow. An empty string means no password, and the build log warns about it. Defaults to *, which disables password login
uidUser ID. When omitted, assigned from a counter starting at 1000 that doesn't skip IDs already in the base image
gidPrimary group ID written to /etc/passwd. When omitted, the user takes the GID of the first entry in groups, which must exist by then or the build fails. With no groups either, the user gets a group of its own name, created with the UID as its GID if it doesn't exist
groupsThe first entry is the primary group (see gid); the user is not added to it as a member. The user joins each remaining group. A group that doesn't exist is skipped with a warning
home, shell, gecosHome directory (default /home/<name>), login shell (default /bin/sh) and full-name field (default the user name)
last_change, min_days, max_days, warn_days, inactive_days, expire_datePassword aging fields for /etc/shadow, as integers

A user that already exists in the base image keeps its /etc/passwd entry; only its /etc/shadow entry is rewritten.

Group fields​

A group's value can be an object with these fields, or empty for a group with an automatically assigned GID.

FieldDescription
gidGroup ID. When omitted, assigned from a counter starting at 1000. For a group already in the base image, a gid that differs from the existing one fails the build
membersUsers in the group. For a group already in the base image, this replaces its member list

A user's disabled and a group's password have no effect, and the CLI warns if you set them. system on a user or group only labels the build log; it doesn't change ID allocation.

Kernel configuration​

The top-level kernel: block defines one or more kernel configurations that runtimes can reference. Two forms are accepted:

# Singleton form — synthesized as the implicit "default" kernel
kernel:
package: kernel-image
version: '*'

# Named map form — multiple kernels for different runtimes
kernel:
yocto-6-6:
package: kernel-image-6.6
version: '*'
yocto-5-15:
package: kernel-image-5.15
version: '*'

Kernel config fields​

Two mutually exclusive modes:

Package mode — kernel installed from an RPM during runtime install:

FieldDescription
packagePackage name (e.g. kernel-image). Mutually exclusive with compile
versionVersion constraint (e.g. *, 6.6.*). Used with package

Compile mode — kernel cross-compiled via sdk.compile.<section> during runtime build:

FieldDescription
compileSDK compile section name (references sdk.compile.<section>). Mutually exclusive with package
installInstall script path — copies kernel artifacts to runtime build dir. Required when compile is set

Command line (either mode, or on its own):

FieldDescription
cmdlineComplete kernel command line, replacing the platform's own. Mutually exclusive with cmdline_extra
cmdline_extraArguments appended to the platform's command line (e.g. isolcpus=4-6, earlycon). Mutually exclusive with cmdline

A kernel: block that sets only cmdline or cmdline_extra is valid, and it does not change where the kernel comes from. The kernel is still selected by the runtime's named reference, the top-level entry, or the platform, exactly as if the block were absent; the project is only changing how that kernel boots. Precedence is per concern: a runtime's cmdline / cmdline_extra wins over the top-level one, while the kernel itself keeps resolving by its own rules. Both resolve per target, so a target-<name>: override at either level is honored. The command line reaches the build and provision hooks as AVOCADO_KERNEL_CMDLINE / AVOCADO_KERNEL_CMDLINE_EXTRA, and editing it alone invalidates the runtime build.

On machines that boot a FIT, the runtime build writes cmdline_extra into every FIT configuration node as avocado,cmdline-extra, covered by the FIT signature. The build fails when cmdline_extra is set without signing.fit_key or signing.fit_unsigned, when the runtime builds no initramfs, or when the value holds a ", ', \, #, & or newline.

Runtime kernel references​

A runtime can reference a named top-level kernel entry or provide an inline override:

runtimes:
dev:
kernel: yocto-6-6 # named reference (string)

prod:
kernel: # inline override (object)
package: kernel-image
version: '6.6.*'

rt:
kernel: # command line only; the kernel itself resolves as if this block were absent
cmdline_extra: 'isolcpus=4-6 nohz_full=4-6'

When kernel: is omitted on a runtime, the CLI falls back to the top-level default kernel entry, or — when no top-level kernel is configured — to the avocado-runtime meta-package's legacy bootfiles behavior.

Var partition configuration​

The runtime var section configures the btrfs-formatted /var partition: a default compression algorithm and a map of subvolumes keyed by path (relative to the var root). Subvolumes can also be declared at the extension level, in which case they travel with the extension; runtime-level entries deep-merge on top and win on conflict.

extensions:
my-ext:
subvolumes:
lib/docker:
nodatacow: true
quota: '10G'
lib/myapp/cache: true # shorthand: writable with defaults

runtimes:
dev:
extensions: [my-ext]
var:
compression: 'zstd:3'
subvolumes:
lib/logs:
writable: true
compression: 'zstd:9' # per-subvolume override
lib/docker:
writable: false # override extension: make read-only

A built-in lib/avocado subvolume is always present (writable). Declaring it explicitly in runtime var.subvolumes suppresses the nested-path warning for extensions that live under it.

var fields​

FieldDefaultDescription
compressionnonePartition-wide default compression (e.g. zstd, zstd:3, lzo, zlib:6, no). Overridden by per-subvolume set
subvolumesMap of path → subvolume entry. Paths are relative to the var root
encryptfalseEncrypt /var as a LUKS2 container keyed to the device's hardware key store
hardwareautoWhich key engine binds it: auto, caam, tpm2, or none. caam/tpm2 fail the boot closed if that engine cannot hold a keyslot; none requires recovery
recoveryName of a registry secret (signing-keys create <name> --algorithm hmac-sha256) that is the master for an operator-held recovery keyslot

encrypt, hardware and recovery are validated at config load — recovery without encrypt, an unknown hardware value, or hardware: none without recovery are all errors. See Encrypted /var for the full workflow.

Subvolume entry forms​

Each map value can be a shorthand or a full object:

FormMeaning
trueEnabled, writable, inherits partition defaults
falseDisabled — suppresses an extension-declared subvolume from a runtime
"ro"Enabled, read-only, inherits partition defaults
object (see below)Full configuration

Subvolume object fields​

FieldDefaultDescription
writabletruefalse makes the subvolume read-only (applied post-mkfs via btrfs property set ro true)
compressioninheritedPer-subvolume compression. Ignored (and skipped) when nodatacow: true — NOCOW disables COW
nodatacowfalseSet the NOCOW inode flag via chattr +C. Useful for databases, VM images, and other random-write workloads
quotanoneQgroup size limit (e.g. 500M, 5G, none). Enables btrfs quotas on the partition when any subvolume sets one
enabledtrueSet to false to suppress an extension-declared subvolume from a runtime

Resolution order​

  1. Built-in lib/avocado (writable).
  2. Extensions from the runtime's extension list, in order — first-listed wins on path conflicts (a warning is emitted for collisions).
  3. Runtime var.subvolumes deep-merges on top, always winning.
  4. Partition-level var.compression applied as the default for subvolumes that don't set their own.
  5. Entries with enabled: false are filtered out.

Subvolume config is included in the runtime input hash, so changes trigger a proper var-image rebuild.

Examples​

Example configuration files are available in the Avocado OS repository. These examples demonstrate common configuration patterns for different use cases and target platforms.