Image Template Reference#
Templates are YAML files that define what goes into a custom OS image, the target platform, packages, disk layout, users, and build-time customizations. This document is the authoritative field-by-field reference for the template format.
For a conceptual overview of how templates fit into the build pipeline, see Understanding the Build Process.
Table of Contents#
What Are Templates and How Do They Work?#
Templates are predefined build specifications that serve as a foundation for building operating system images. Here’s what templates empower you to do:
Create standardized baseline configurations.
Impose consistency across multiple images.
Reduce duplication of effort.
Share and reuse common configurations with your team.
The OS Image Composer provides default image templates on a per-distribution basis and image type (RAW vs. ISO) that can be used directly to build an operating system from those defaults. You can override these default templates by providing your own template and configure or override the settings and values you want. The tool will internally merge the two to create the final template used for image composition.
How Templates Work#
OS Image Composer ships default templates for each distribution and image type (raw, ISO, initrd). When you provide a user template, the tool merges it with the matching default; your values override or extend the defaults. The merged result is validated against a JSON schema before the build begins.
Default templates live at:
config/osv/<target.os>/<target.dist>/imageconfigs/defaultconfigs/default-<imageType>-<arch>.yml
Note:
imageType: imgmaps todefault-initrd-<arch>.yml(there is nodefault-img-filename).
You do not need to edit the defaults. You can start from one of the examples in
image-templates/ and override only what you need.
Quick Start Example#
A minimal user template only needs image, target, and optionally
systemConfig with extra packages:
image:
name: my-edge-device
version: "1.0.0"
target:
os: edge-microvisor-toolkit
dist: emt3
arch: x86_64
imageType: raw
systemConfig:
name: edge
packages:
- cloud-init
- rsyslog
Everything else (disk layout, bootloader, kernel, default packages) comes from
the default template for emt3 / raw / x86_64.
Top-Level Structure#
A template file has up to five top-level sections plus an optional metadata
block:
metadata: # Optional - AI-searchable discovery metadata
...
image: # Required - image name and version
...
target: # Required - OS, distribution, architecture, image type
...
disk: # Optional - disk layout, partitions, output artifacts
...
packageRepositories: # Optional - additional package repositories
- ...
systemConfig: # Required in merged template - packages, kernel, users, etc.
...
Note: User templates require only
imageandtarget. The remaining sections are merged from the default template if omitted.
Field Reference#
metadata#
Optional block for AI-powered template discovery. Ignored by the build engine.
Field |
Type |
Description |
|---|---|---|
|
string |
Human-readable description of the template |
|
string[] |
Use cases this template targets |
|
string[] |
Keywords for search and discovery |
metadata:
description: "Edge device image with container runtime"
use_cases: ["edge computing", "IoT gateway"]
keywords: [edge, docker, emt3]
image (required)#
Image identification. Both fields are required.
Field |
Type |
Required |
Validation |
Description |
|---|---|---|---|---|
|
string |
Yes |
|
Image name (alphanumeric, hyphens, underscores) |
|
string |
Yes |
Semver-like: |
Version string |
image:
name: my-edge-device
version: "1.0.0"
target (required)#
Target platform. All four fields are required.
Field |
Type |
Required |
Valid Values |
Description |
|---|---|---|---|---|
|
string |
Yes |
|
Target operating system |
|
string |
Yes |
See OS constraints below |
Distribution identifier |
|
string |
Yes |
|
Target CPU architecture |
|
string |
Yes |
|
Output image format |
OS → dist constraints:
OS |
Valid |
|---|---|
|
|
|
|
|
|
|
Any (e.g., |
|
Any (e.g., |
target:
os: ubuntu
dist: ubuntu24
arch: x86_64
imageType: raw
disk#
Disk layout, partition scheme, and output artifact formats. If omitted, the default template provides sensible values (typically 4–6 GiB GPT disk with EFI boot and ext4 root partitions).
Field |
Type |
Required |
Description |
|---|---|---|---|
|
string |
Yes (schema) |
Disk configuration name (e.g., |
|
string |
No |
Disk device path (used by live installer, e.g., |
|
string |
No |
Disk size. Accepts: |
|
string |
No |
|
|
artifact[] |
No |
Output formats and optional compression |
|
partition[] |
No |
Partition layout definitions |
disk.artifacts[]#
Each entry defines one output format:
Field |
Type |
Required |
Valid Values |
Description |
|---|---|---|---|---|
|
string |
Yes |
|
Output image format |
|
string |
No |
|
Compression to apply |
disk.partitions[]#
Each entry defines one partition:
Field |
Type |
Description |
|---|---|---|
|
string |
Partition identifier (e.g., |
|
string |
Partition label |
|
string |
Partition type (e.g., |
|
string |
GPT type GUID (e.g., |
|
string |
Filesystem type: |
|
string |
Filesystem label |
|
string |
Start offset (e.g., |
|
string |
End offset ( |
|
string |
Mount point (e.g., |
|
string |
Mount options (e.g., |
|
string[] |
Partition flags (e.g., |
Example - raw disk with two partitions and two output formats:
disk:
name: Edge_Raw
size: 4GiB
partitionTableType: gpt
artifacts:
- type: raw
compression: gz
- type: vhdx
partitions:
- id: boot
type: esp
flags: [esp, boot]
start: 1MiB
end: 513MiB
fsType: fat32
mountPoint: /boot/efi
mountOptions: umask=0077
- id: rootfs
type: linux-root-amd64
start: 513MiB
end: "0"
fsType: ext4
mountPoint: /
mountOptions: defaults
packageRepositories#
Optional list of additional package repositories beyond the OS base repos.
Field |
Type |
Required |
Description |
|---|---|---|---|
|
string |
Yes |
Repository identifier (e.g., |
|
string |
Yes |
Repository base URL (must be a valid URI) |
|
string |
Yes |
GPG key URL, absolute file path, or |
|
string |
No |
Repository component (e.g., |
|
int |
No |
Priority from |
|
string[] |
No |
Specific packages to include from this repo (package pinning) |
packageRepositories:
- codename: "company-internal"
url: "https://packages.example.com/repo"
pkey: "https://packages.example.com/gpg.key"
component: "main"
priority: 100
- codename: "dev-tools"
url: "https://dev.example.com/repo"
pkey: "[trusted=yes]"
See Multiple Package Repository Support for detailed configuration guidance.
systemConfig#
System configuration - packages, kernel, users, bootloader, build-time commands, and more. Required in the final merged template, but optional in user templates (as defaults already provide a complete base).
Field |
Type |
Required |
Description |
|---|---|---|---|
|
string |
No |
Configuration name |
|
string |
No |
Human-readable description |
|
string |
No |
System hostname |
|
string[] |
No |
Packages to install (additive with defaults) |
|
object |
No |
Kernel configuration |
|
object |
No |
Bootloader configuration |
|
object |
No |
dm-verity / Secure Boot configuration |
|
user[] |
No |
User account definitions |
|
object |
No |
Initramfs config (ISO/initrd builds) |
|
file[] |
No |
Extra files to copy into the image |
|
cmd[] |
No |
Shell commands to run during build |
Package names must match: ^[A-Za-z0-9](?:[A-Za-z0-9+_.:~-]*[A-Za-z0-9+])?$
and must be unique within the list.
systemConfig.kernel#
Field |
Type |
Description |
|---|---|---|
|
string |
Kernel version (e.g., |
|
string |
Kernel boot command line |
|
string[] |
Kernel packages (e.g., |
|
string |
Additional kernel modules to load |
|
bool |
Enable Unified Kernel Image (typically set by defaults) |
systemConfig:
kernel:
version: "6.14"
cmdline: "console=ttyS0,115200 console=tty0 loglevel=7"
packages:
- linux-image-generic-hwe-24.04
# Optional additional repositories
packageRepositories:
- codename: emtNext
url: https://example.com/rpms/next/base
pkey: https://example.com/RPM-GPG-KEY
priority: 1001
allowPackages:
- kernel-6.17.11
- kernel-drivers-gpu-6.17.11
- libva*
- codename: edgeai
url: https://example2.com/edgeai/
pkey: https://example2.com/edgeai/GPG-PUB-KEY.gpg
priority: 500
systemConfig.bootloader#
Field |
Type |
Valid Values |
Description |
|---|---|---|---|
|
string |
|
Boot firmware type |
|
string |
|
Bootloader software |
Typical defaults: raw images use efi / systemd-boot; ISO images use
efi / grub.
systemConfig.immutability#
Configures dm-verity immutable root filesystem and optional UEFI Secure Boot signing.
Field |
Type |
Required |
Description |
|---|---|---|---|
|
bool |
Yes (when section present) |
Enable dm-verity immutable root |
|
string |
Conditional |
Private key file ( |
|
string |
Conditional |
Certificate in PEM format ( |
|
string |
Conditional |
Certificate in DER format ( |
Note: If any Secure Boot field is provided, all three must be provided and
enabledmust betrue.
systemConfig:
immutability:
enabled: true
secureBootDBKey: /path/to/db.key
secureBootDBCrt: /path/to/db.crt
secureBootDBCer: /path/to/db.cer
systemConfig.users[]#
Field |
Type |
Required |
Description |
|---|---|---|---|
|
string |
Yes |
Username |
|
string |
No |
Password (plain text or pre-hashed with |
|
string |
No |
Hash algorithm: |
|
int |
No |
Max password age in days |
|
string |
No |
Script to run on login |
|
string[] |
No |
Additional groups |
|
bool |
No |
Grant sudo permissions |
|
string |
No |
Custom home directory |
|
string |
No |
Login shell (e.g., |
systemConfig:
users:
- name: admin
password: "changeme"
sudo: true
groups: [docker, wheel]
shell: /bin/bash
- name: service-account
shell: /usr/sbin/nologin
systemConfig.initramfs#
Used for ISO and initrd builds. Points to the initramfs configuration template.
Field |
Type |
Required |
Description |
|---|---|---|---|
|
string |
Yes (when section present) |
Path to the initramfs config template file |
systemConfig.additionalFiles[]#
Copy host files into the image at build time.
Field |
Type |
Description |
|---|---|---|
|
string |
Source path on the host (absolute, or relative to template directory) |
|
string |
Destination path inside the image |
systemConfig:
additionalFiles:
- local: files/dhcp.network
final: /etc/systemd/network/dhcp.network
- local: files/motd
final: /etc/motd
systemConfig.configurations[]#
Shell commands executed inside the chroot during the configuration stage.
Field |
Type |
Description |
|---|---|---|
|
string |
Shell command to execute |
systemConfig:
configurations:
- cmd: systemctl enable docker
- cmd: echo "BuildDate=$(date)" >> /etc/image-info
Package Repositories#
Use packageRepositories to add extra Debian or RPM repositories to a build.
Each entry defines where to fetch package metadata and how candidates are
selected when the same package exists in multiple repositories.
Repository Fields#
codename: repository identifier.url: repository base URL.component: optional Debian component (for example,main,universe) for multi-component repositories.pkey: GPG key reference; supportshttp:///https://URLs,file://URLs, absolute local paths, or[trusted=yes]for supported Debian flows.priority: numeric repository preference used in conflict resolution.allowPackages: optional package white list for metadata filtering.
Priority Behavior#
priority is evaluated during package candidate selection across repositories.
Higher numeric values are preferred.
Debian resolver also supports APT-like behavior:
< 0: block packages from that repository990: prefer over default repositories1000: install even if lower version> 1000: force preference
When candidates have equivalent priority, version constraints and dependency context determine the final package choice.
AllowPackages White List#
allowPackages limits which package names are indexed from a specific
repository.
If omitted or empty, all repository packages are eligible.
If present, only matching package names are indexed.
Supported matching modes:
exact name (for example
spice-server)prefix/version pin (for example
kernel-6.17.11)glob patterns (for example
libva*,wayland*)
Filtering happens at metadata-parse time, before dependency resolution.
Template Merge Behavior#
When your user template is merged with the default template, different sections follow different strategies:
Section |
Strategy |
|---|---|
|
User overrides default if non-empty |
|
User value used entirely |
|
User replaces entire default if non-empty |
|
Additive - user packages appended to defaults (deduplicated) |
|
User overrides |
|
User overrides individual fields if non-empty |
|
Merged by |
|
Merged by |
|
Additive - user commands appended after defaults |
|
Merged only if user explicitly provides the section |
|
Merged by |
Variable Substitution#
Templates support variable substitution using ${variable_name} syntax. You
can provide variable values via a separate YAML file or command-line flags at
build time.
To learn how variables interact with each build stage, see Build Stages in Detail.
Best Practices#
Start from examples - copy a template from
image-templates/and modify only the fields you need. Let defaults handle the rest.Keep templates minimal - override only what differs from the default. Smaller templates are easier to maintain and review.
Use descriptive names - name images and configs after their purpose (e.g.,
factory-floor-edge, nottest-image-3).Version control your templates - store them in Git alongside your deployment code.
Validate before building - run
os-image-composer validate template.ymlto catch errors early.Prefer
additionalFilesoverconfigurations- copying config files is more reproducible than running arbitrary shell commands.