TL;DR:

  • Yocto Project builds minimal, reproducible Linux images for embedded and edge devices, giving you full control over what goes into the OS
  • It uses a layered recipe system (BitBake) — you add layers for hardware support (BSPs), middleware, and your application, then build a complete image
  • The learning curve is steep, but the payoff is a locked-down, updatable, reproducible image — exactly what edge devices at scale require

Deploying a full Ubuntu or Debian image on an edge device works well enough in development. In production — especially at scale, on constrained hardware, in a security-sensitive environment — you want something leaner. The Yocto Project exists precisely for this: building a custom Linux distribution that contains exactly what your device needs and nothing else.

Yocto is not a Linux distribution in itself. It is a build system and set of tools for creating Linux distributions for embedded targets. The result can be a 50MB root filesystem for an industrial gateway or a 500MB image for a more capable edge compute node. You define it; Yocto builds it reproducibly.

Core Concepts

BitBake is the build engine at Yocto’s core. It reads recipe files (.bb and .bbappend) and executes tasks: fetching source code, configuring builds, compiling, and packaging. BitBake handles dependency resolution and parallel builds across tasks.

Recipes (.bb files) describe how to build a single piece of software — where to fetch the source, how to configure and compile it, what to install into the image. The Yocto community maintains thousands of recipes covering the open-source software stack.

Layers are collections of recipes, configuration files, and supporting scripts, organised around a theme. Layers stack on top of each other:

  • openembedded-core — the minimal core layer
  • meta-openembedded — common open-source packages
  • meta-raspberrypi, meta-intel, meta-arm — Board Support Package layers for specific hardware
  • meta-mycompany — your own layer with your application and customisations

This layering approach means you can update a BSP layer when new hardware support is released without touching your application layer, and vice versa.

Distros and images define the feature set of the final output. poky is Yocto’s reference distribution. You typically create your own distro configuration to set the C library (glibc or musl), package manager (rpm, deb, ipk, or none), and feature flags. An image recipe (core-image-minimal, core-image-base, or your own) specifies which packages to include.

Getting Started

Yocto requires a Linux host (Ubuntu 22.04 or 24.04 are well-supported). The build process is resource-intensive — expect 50–100GB of disk space for a full build and several hours on first run (subsequent builds use caching).

# Clone Poky (Yocto's reference distribution)
git clone -b scarthgap https://git.yoctoproject.org/poky.git
cd poky

# Set up the build environment
source oe-init-build-env build

# Edit conf/local.conf to set your target machine
echo 'MACHINE = "raspberrypi4-64"' >> conf/local.conf

# Add the Raspberry Pi BSP layer
git clone -b scarthgap https://git.yoctoproject.org/meta-raspberrypi \
  ../meta-raspberrypi

bitbake-layers add-layer ../meta-raspberrypi

# Build a minimal image
bitbake core-image-minimal

The scarthgap branch is the current LTS release (Yocto 5.0). The MACHINE variable selects the target hardware — BSP layers provide machine configurations for specific boards. After the build completes, you’ll find the image in tmp/deploy/images/raspberrypi4-64/.

Writing Your Own Layer and Recipe

For your application, you create your own layer:

# Create a new layer
bitbake-layers create-layer ../meta-myapp
bitbake-layers add-layer ../meta-myapp

Within the layer, a recipe for your application looks like this:

# meta-myapp/recipes-myapp/myapp/myapp_1.0.bb

SUMMARY = "Edge data collector application"
DESCRIPTION = "Reads sensor data and publishes to MQTT broker"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "git://github.com/mycompany/myapp.git;protocol=https;branch=main"
SRCREV = "a1b2c3d4e5f6..."  # Pin to a specific commit

S = "${WORKDIR}/git"

inherit cmake

DEPENDS = "mosquitto"  # Build-time dependency

# Install the binary
do_install() {
    install -d ${D}${bindir}
    install -m 0755 myapp ${D}${bindir}/
}

# Add systemd service file
inherit systemd
SYSTEMD_SERVICE:${PN} = "myapp.service"

You then create an image recipe that extends a base image and adds your package:

# meta-myapp/recipes-core/images/myapp-image.bb

require recipes-core/images/core-image-minimal.bb

IMAGE_INSTALL:append = " myapp openssh"

# Include only what you need
IMAGE_FEATURES:append = " ssh-server-openssh"

Key Configuration for Edge Deployments

Read-only rootfs: For field devices, a read-only root filesystem prevents accidental modification and simplifies recovery:

# In local.conf or your distro config
IMAGE_FEATURES:append = " read-only-rootfs"

Writable data goes to a separate partition mounted at /data or similar.

Image signing: For OTA update security, Yocto integrates with Mender, RAUC, and SWUpdate for signed image updates. These handle A/B update partitions and rollback on failed updates — essential for unattended edge devices.

Minimal footprint: Remove package managers and build tools from production images:

# In your image recipe
IMAGE_FEATURES:remove = " package-management"
EXTRA_IMAGE_FEATURES:remove = " debug-tweaks"

SDK generation: Yocto can generate a cross-compilation SDK for your developers — a toolchain that matches the exact compiler and libraries used in the device image:

bitbake myapp-image -c populate_sdk

The resulting SDK installer produces a self-contained toolchain your developers can use without needing a full Yocto build environment.

When Yocto Makes Sense

Yocto is a significant investment. The build system has a steep learning curve, and maintaining a Yocto layer setup across multiple hardware targets and software versions is non-trivial. It makes sense when:

  • You are deploying at meaningful scale (dozens to thousands of devices)
  • Security hardening and minimal attack surface are priorities
  • You need reproducible, signed, OTA-updatable images
  • Your hardware has specific BSP requirements not met by a standard distro

For smaller deployments, simpler approaches often suffice: a hardened Raspberry Pi OS image with Ansible provisioning, Balena for containerised edge deployments, or Buildroot for very constrained targets where Yocto’s build overhead is impractical.

Yocto’s position in the edge ecosystem has strengthened considerably as industrial IoT deployments scale up and security requirements tighten. If you’re building a product that ships Linux to field devices and will be in service for five or more years, the upfront investment in a proper Yocto setup pays back in maintainability, security, and the ability to support hardware revisions without rebuilding your entire software stack.