# sonic-buildimage: the make system behind a SONiC network image

> The sonic-buildimage repository holds the scripts that turn the SONiC source tree into an installable binary image for switching hardware. Its README is a wall of Azure DevOps badges, one per platform and release branch, and the interesting engineering is in the Makefile switches that decide which Debian release a build is based on.

**sonic-net/sonic-buildimage** — Scripts which perform an installable binary image build for SONiC

- Repository: https://github.com/sonic-net/sonic-buildimage
- Stars: 1,039 · Forks: 2,002
- Language: C
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/sonic-net-sonic-buildimage

## What the repository actually holds

The description of the repository is one line: scripts which perform an installable binary image build for SONiC. Everything in the root is a piece of that sentence.

There are the shell scripts that drive the build, `build_image.sh`, `build_docker.sh`, `build_debian.sh`, `build_debug_docker_j2.sh`, `get_docker-base.sh` and `push_docker.sh`, plus `functions.sh` for the shared shell functions and `update_screen.sh`. There is `check_install.py` and `install_sonic.py` for the installation side, and `pytest.ini` for the Python tests that go with it.

The supporting directories are the important part. `platform/` holds the per-platform configuration, `src/` holds the SONiC source that the build consumes, `rules/` and `scripts/` hold the make logic, and `dockers/` holds the container definitions. The `sonic-slave-*` directories are the build environments, one per Debian generation: bookworm, bullseye, buster, jessie, stretch and trixie. There is also `device/`, `files/`, `installer/`, `tools/`, `tests/` and `vex/`.

Two more root files are worth naming. `validated-submodule-commits` is a list of the submodule commits that have been validated, which is how a repository full of pinned dependencies knows which pins are known good. And `ThirdPartyLicenses.txt` plus `README.sbom.md` are the software bill of materials side of an image build, which for a distribution that goes into a network switch is a supply chain document rather than a formality.

The project is not archived, the last push was on 2026-10-15, and the primary language is C, which is the language of the software the image is building rather than of the build itself.

## The platform matrix is the README

The README of this repository is not prose, it is a grid of build status badges, and reading it as a grid is the fastest way to understand the scope of the project.

Each badge points at one Azure DevOps definition in the `mssonic/build` project, and there is one per hardware platform per source branch. The platforms are Broadcom, Mellanox, Marvell Teralynx, Marvell Prestera on armhf, Marvell Prestera on arm64, Nvidia Bluefield, and VS, which is the virtual switch. The branches are master, and then the dated release branches 202605, 202511, 202505 and 202411.

So the image is built seven ways, on seven platform configurations, from five source lines, and the README is the status board for all of them. The presence of dated branches is the interesting part, because it shows the lifetime of a SONiC release line, and the fact that the 202411 line still has badges for most platforms means the older branches are still being built rather than being frozen artefacts.

The badges also expose the asymmetry in the support matrix. On the 202505 branch the Prestera entries are labelled simply Marvell, without the armhf and arm64 split, and the 202411 section is cut off in the visible part of the README. The naming and the set of platforms per branch is therefore the most useful metadata in the repository, and it is public.

This is also a repository where the CI configuration is not in the repository. The `azure-pipelines.yml` file and the `.azure-pipelines/` directory at the root hold part of it, but the definitions the badges point at live in Azure DevOps, and the badge URLs carry the definition ids, which tells you that the pipeline definitions are maintained in the CI system rather than alongside the code.

## Debian releases are make variables, and Bazel is trixie only

The Makefile is where the build policy lives, and the first thing it does is decide which Debian generations are in play.

```makefile
NOJESSIE ?= 1
NOSTRETCH ?= 1
NOBUSTER ?= 1
NOBULLSEYE ?= 1
NOBOOKWORM ?= 0
NOTRIXIE ?= 0
```

A `?=` assignment means the value can be overridden from the environment or the command line, and a value of 1 means that generation is excluded. So the default build excludes jessie, stretch, buster and bullseye, and includes bookworm and trixie, which is the list of distributions a new build should use.

The next part of the file is the interesting one, because it fails the build rather than producing something broken. Bazel components only support a subset of configurations, and the Makefile checks the readiness variable before it starts:

```makefile
BAZEL_NON_TRIXIE_BUILDS := $(strip $(BUILD_JESSIE) $(BUILD_STRETCH) $(BUILD_BUSTER) $(BUILD_BULLSEYE) $(BUILD_BOOKWORM))
```

If any of those is set, the make invocation stops with an error that names the problem and gives the fix: the Bazel dockers require the trixie base, and the message spells out the exact variable combination to re-run with, or the `bazel_disabled` value for the readiness variable. That is an unusual thing to find in a Makefile, a build that refuses a configuration it cannot support with an error rather than a warning, and it saves every user of the build from discovering the problem as a missing artefact three hours in.

The second half of the file turns the switches into per-distro build flags, so a generation that is enabled contributes a `BUILD_` variable that the rest of the make logic consumes.

## The platform configuration is a Jinja template

After the distribution switches, the Makefile resolves the platform, and the mechanism is worth a look because it is how a single source tree produces a different image per ASIC.

```makefile
PLATFORM_PATH := platform/$(if $(PLATFORM),$(PLATFORM),$(CONFIGURED_PLATFORM))
PLATFORM_CHECKOUT := platform/checkout
PLATFORM_CHECKOUT_FILE := $(PLATFORM_CHECKOUT)/$(PLATFORM).ini
PLATFORM_CHECKOUT_CMD := $(shell if [ -f $(PLATFORM_CHECKOUT_FILE) ]; then PLATFORM_REPO=$(PLATFORM_REPO) PLATFORM_REF=$(PLATFORM_REF) PLATFORM_PATH=$(PLATFORM_PATH) j2 $(PLATFORM_CHECKOUT)/template.j2 $(PLATFORM_CHECKOUT_FILE); fi)
MAKE_WITH_RETRY := ./scripts/run_with_retry $(MAKE)
```

The platform path resolves to `platform/` plus either the platform given on the command line or the configured one, and the per-platform settings live in an ini file under `platform/checkout/`. That ini is not read directly, it is rendered: the `j2` tool, which is Jinja for the command line, expands `template.j2` with the platform repository and the platform ref, producing the concrete configuration for the ASIC in hand. So the platform description is a template, and the values that differ per platform are variables in it.

The `PLATFORM_REPO` and `PLATFORM_REF` variables are the two knobs that make this work across the matrix, because the platform configuration is itself fetched from a repository at a given reference, which is how a branch can be rebuilt with a different platform definition without touching the source tree.

The last line of that excerpt is the other piece of build policy. Every recursive make invocation goes through `./scripts/run_with_retry`, so a sub-make that fails is retried rather than losing the whole build to a transient network or registry failure, which in a build that pulls a large number of artefacts is the difference between a flaky pipeline and a reliable one.

## The documentation that is not in the README

The README is badges, so everything a newcomer needs is in files next to it, and the naming tells you what each one is for.

`README.buildsystem.md` is the description of the build system itself, which is the document to read first. `README.sbom.md` covers the software bill of materials, the inventory of what is in the image. `README.arm64_build_on_amd64.md` covers the specific problem of building an arm64 image on an amd64 machine, which is a real constraint in a CI fleet that is mostly x86.

The remaining root files are the ones that hold the build accountable. `MAINTAINERS` records who owns what, `.artifactignore` controls what the pipeline publishes, `.gitmodules` and `validated-submodule-commits` control the pinned dependencies, and `ThirdPartyLicenses.txt` is the licence inventory for everything that is not the project's own code.

That last pair is the part worth dwelling on for a network operating system. An image that runs on a switch carries a GPL userland, a set of vendor device drivers, and a build that pulls from dozens of repositories at pinned commits. A file listing the third party licences and a file listing the validated submodule commits are the two documents that make it possible to answer the question a security review always asks, which is what is actually in this thing.

The `Makefile.cache` and `Makefile.work` files alongside the main `Makefile`, and the `slave.mk` file, are the standard way a make system of this size splits its logic: the entry point stays short and the detail moves into includes.

## Where this build system is the wrong tool

The limits are about what the build is for, and they are sharp.

The first is that the image is for network hardware. The matrix names Broadcom, Mellanox, Marvell Teralynx, Marvell Prestera, Nvidia Bluefield and the virtual switch, and the platform configuration is a per-ASIC ini that the build renders into the filesystem layout, the device tree, the kernel and the userland. A team that wants a SONiC image for a platform not in that list is not going to adapt the build, they are going to write a platform definition and hope the rest generalises, and the virtual switch target is the one that suggests it can.

The second is that the build assumes a large CI. The pipeline definitions live in Azure DevOps, the build runs in containers pulled from a base image, and the design uses retries, caches and a matrix of branches. Reproducing it locally is possible, and the presence of `build_debug_docker_j2.sh` and the `sonic-slave-*` images says the maintainers do it, but a single developer reproducing a seven platform matrix on one machine is not the use case this was built for.

The third is the make and shell substrate. The build is a make tree that shells out to Docker, Python and j2, with policy expressed in `?=` variables and platform selection in a template. That is a workable design and it is a large one, and the size is visible in the number of Debian generations the file has to know about, which is the residue of a decade of supporting the platforms that were current at the time.

The alternative for a team that wants to run SONiC is to use the published images rather than to build them, and the difference in approach is that this repository assumes you are the operator of the hardware and the vendor of the image, while the alternative assumes you are a user of somebody else's. For an organisation that ships its own images to its own fleet, the first is the only option, and the cost of it is the platform matrix you have to keep green.

## Conclusion

sonic-buildimage fits a team that produces SONiC images for its own switching hardware, that has to reproduce a specific vendor platform configuration, and that wants the build to be a repeatable function of a platform ini. It is the wrong tool for a team that only wants to run SONiC, since the images are published for that, and it is the wrong choice for a general build because the system is tuned for the handful of ASICs in the matrix. Before adopting it, read `README.buildsystem.md` for the build system itself, check which of the release branches the CI matrix still builds, and note that the repository carries a licence the GitHub classifier cannot name, so read the `LICENSE` file rather than assuming the terms of the surrounding SONiC projects.

## FAQ

### What does the sonic-buildimage repository do?

It holds the scripts that perform an installable binary image build for SONiC, producing the filesystem images that boot on the supported network hardware. The root carries the build scripts, the platform configuration, the source, the per-Debian build environments and the installation tooling.

### Which platforms does the SONiC build image support?

The CI matrix in the README covers Broadcom, Mellanox, Marvell Teralynx, Marvell Prestera on armhf and arm64, Nvidia Bluefield and the virtual switch, across the master branch and the dated release branches 202605, 202511, 202505 and 202411.

### Which Debian versions can the SONiC build image be built from?

The Makefile has switches for jessie, stretch, buster, bullseye, bookworm and trixie, with the older generations excluded by default. The Bazel based build supports only trixie, and the build fails fast with an explanatory error if another combination is requested.

### How does the SONiC build select a platform configuration?

Through PLATFORM_PATH, which resolves to platform/$(PLATFORM) or the configured platform, and the per-platform ini file is rendered from a Jinja template with j2, using the platform repository and the platform ref as the inputs.

## Sources

- [Issues](https://github.com/sonic-net/sonic-buildimage/issues)
- [README](https://github.com/sonic-net/sonic-buildimage/blob/master/README.md)
- [sonic-net/sonic-buildimage on GitHub](https://github.com/sonic-net/sonic-buildimage)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sonic-net-sonic-buildimage
