Overlays
An overlay is an out-of-tree directory of config layers that boot2deb merges on top
of the shipped tree. It is how you keep your devices, recipes, and retunings in your
own repo — versioned, private, and never a fork of the vendored config. Pass one (or
several) with the global --overlay <dir> flag, on any command:
boot2deb --overlay ~/my-boards build my-tablet/forky
Each --overlay must name an existing directory. An empty or mistyped path is a
resolve-time error rather than a silent no-op. An empty one would resolve every asset
against the current directory, and a typo would shadow nothing at all. Either way the
build would quietly use a config tree you did not intend, which is exactly what an
overlay exists to make explicit.
An overlay has the same directory layout as the shipped root. That is any subset of
devices/, socs/, arches/, boot-methods/, kernels/, features/, recipes/,
plus fragments/, blobs/, and per-layer overlay/ trees. You ship only the files you
add or change, and everything else resolves from the shipped tree underneath.
An overlay is just a second config search root, so everything the CLI does sees the
merged tree. That covers resolve and doctor, the verify-* and list-* commands,
and build.
What an overlay can do
- Retune one value. An overlay
devices/turing-rk1.tomlholding onlyimage_size = "8G"changes that one field — every other key merges from the shipped file (see merge semantics). - Add to a list. Add a
supported_kernel, an extra rootfs package, another[[apt_sources]]— by restating the array with your addition (arrays are replaced wholesale, not concatenated). - Add a whole target. Drop in a new
devices/my-tablet.toml,socs/…,kernels/…,features/…, orrecipes/…. It lists and builds alongside the shipped ones, becauselist-devices,list-recipes, and friends union the overlay’s targets in.
How overlays merge
The search path is the shipped root first, then each --overlay in the order given.
Later wins, and any overlay wins over the shipped root. When the same layer file
(e.g. devices/turing-rk1.toml) exists in more than one root, the copies are
deep-merged:
- Tables merge key-by-key, recursing into nested tables — so setting one field leaves its siblings intact.
- Scalars and arrays are replaced wholesale — an overlay array sets the value, it does not append. To add one entry to a shipped list, restate the list with your entry included.
A layer file present only in an overlay simply adds a new target (nothing to merge).
Fragments, blobs, and per-feature/-layer rootfs trees (overlay/, overlay-pre/ and
overlay-nonfree/) resolve along the same path. A same-named asset in an overlay shadows
the shipped one, while rootfs trees present in both roots stack (shipped first, overlay
last).
The three rootfs trees
A layer can carry up to three trees, which differ in when they are laid in and whether they are:
| Tree | Laid in | Carried by |
|---|---|---|
overlay-pre/ | before any package installs, so a maintainer script sees the config while it runs | any layer |
overlay/ | after every package, so it wins over whatever a package shipped | any layer |
overlay-nonfree/ | with overlay/, and only when the build is not libre | a SoC or device layer |
overlay-nonfree/ is where a hardware layer vendors nonfree firmware Debian does not
package — on the RK3288 that is the two Broadcom blobs in socs/rk3288/overlay-nonfree/.
It stacks directly after its own layer’s overlay/, so a board’s own file still wins
over what it extends. It is a separate tree rather than a subtraction from overlay/,
so that every blob a layer ships sits in one directory you can audit. A libre build
skipping it therefore cannot miss one by spelling a path wrong.
File modes in a rootfs overlay/ tree
A per-layer overlay/, overlay-pre/ or overlay-nonfree/ tree is copied into the
image. Its modes are normalized to git’s own file model on the way in.
Directories become 0755, and a file becomes 0755 if its executable bit is set and
0644 otherwise. Symlinks are untouched.
That is the identity function on everything a git tree can express, since git records
exactly 100644 and 100755, and no directory mode at all. It discards the one thing a
git tree cannot express: your umask at checkout time. Set the executable bit on a hook
and it stays executable in the image. Everything else about the mode is not yours to
choose here.
If a file needs a mode outside those two, an overlay tree is the wrong place for it. A
git checkout cannot carry that mode to begin with. A 0440 sudoers drop-in and a 0700
home are the usual cases. Ship it from a first-boot hook, which runs as root on the
board.
Locks land in the owning overlay
update writes a recipe’s lock, and build --save-manifest writes its solved manifest,
into the root that owns the recipe. build --save-outputs writes its outputs record
there too. An overlay recipe’s lock and manifest therefore land in that overlay, beside
the recipe, not in the shipped tree. An out-of-tree recipe
stays fully self-contained: recipe, lock, and manifest are all versioned together in
your repo.
The keyring is a fixed trust anchor
One asset an overlay cannot silently replace is the Debian archive keyring
(blobs/keyrings/debian-archive-keyring.gpg). It is the trust root for the rootfs
bootstrap, so an overlay that ships its own copy is refused with a fail-closed
error. An overlay must not be able to swap the bootstrap’s trust anchor. If you
genuinely intend to use the overlay’s keyring, opt in explicitly with
build --unsafe-overlay-keyring. Every other asset follows the normal
highest-precedence-wins rule, and only this trust anchor is pinned to the shipped root.
Overlay or in-tree edit?
Two paths, chosen by intent:
- Overlay — you are bringing up your own board, or tuning a build for yourself. Keep
it out-of-tree with
--overlay. There is nothing to upstream and nothing to fork. - In-tree edit — you are contributing a board back to boot2deb. Edit the vendored tree directly and open a pull request.
Adding a board walks through the layers to write, and applies to both paths. The only difference is whether the files land in your overlay or in the vendored tree.