📦 Release first ⏩ Ship faster ⚡

⚖️ Adding Debian — and what it weighs

[yoe] started Alpine-first: musl, busybox, OpenRC, and apk. That stack is small, fast, and clean to wrap, and it remains the default for new projects. But not every workload fits it. Some binaries are built for glibc and never ported to musl — CUDA, vendor camera and radio drivers, a lot of enterprise software. Some teams already run a Debian/Ubuntu-based fleet and want their edge devices to match it. And the apt ecosystem is vast.

So [yoe] now has a second backend: Debian. The latest video walks through it. The same project can build Alpine and Debian images side by side, choosing the distro per image. A unit's source build runs in whichever toolchain the consuming image needs — musl for an Alpine image, glibc for a Debian one — and produces a libc-correct binary either way. You pick the platform the workload requires, image by image.

The same machinery, a much bigger feed

Under the hood, the Debian backend reuses the unit model Alpine already runs on. [yoe] targets Trixie, Debian's current stable release, and Debian main alone exposes nearly 69,000 packages — against roughly 25,000 in Alpine's main and community repos combined. Rather than ingest all of that up front, [yoe] parses the package index files on startup and materializes units on demand, exactly as it does for Alpine. Even against a feed that size, the TUI still comes up in about a second.

The one place the two worlds diverge is naming. The same library often goes by a different package name on each base — Python is python3 on Alpine but python3.11 on Debian — so a unit now carries per-distro build and runtime dependencies, and the build system resolves the right ones for the image it's assembling. Some source packages needed adjusting to compile cleanly against either base, but once that's done a single unit builds on both. Picking a platform is then just a project setting: flip the default distro between Alpine and Debian and rebuild.

Choose per image, pay only where you need it

[yoe] lets you reach for the base distribution without committing the whole project to it. If you don't have a hard reason for Debian — a glibc-only library, a vendor binary, an existing Debian fleet — Alpine keeps the image small and the defaults work. If you do, Debian's plumbing is there: feeds resolve, packages mirror, the rootfs assembles in a single mmdebstrap pass, and the project's own repo emits a signed index.

The pattern this enables is mixing the two in one project — a glibc Debian host image running vendor agents and a container runtime, with small musl Alpine application containers deployed inside it. The host pays for compatibility where it needs it; the workloads stay lean. You spend the extra megabytes exactly once, exactly where they earn their place, instead of across the whole device.

The tradeoff is size

Debian buys compatibility, and it costs space. To measure that honestly, we built the same minimal image on each backend: the smallest thing that boots and accepts an SSH login, with no extra developer tooling on either side. Just a kernel, an init system, libc, a shell, the package manager, sshd, DHCP networking, and a login user. Same job, same qemu-x86_64 target.

BackendPackages availableMinimal ssh-image rootfsDev image assembly
Alpine~25,00085 MB~10 s
Debian~69,000405 MB~100 s

Debian's draw is the catalog — about 69,000 packages in main, against Alpine's ~25,000 across main and community. The cost is size and time: roughly 4.8× on disk — the apples-to-apples platform floor for a real device you can log into — and close to 10× in assembly. The build-time column is the cached image-assembly step for the dev image, a notch up from this minimal one; the sections below break down where each gap comes from.

Where the difference comes from

Two things, and most of it is the kernel.

The kernel. Most of the gap is the stock linux-image-amd64 package — its module tree alone is about 107 MB, because a distribution kernel ships a driver for every machine it might ever run on. Alpine here boots a kernel [yoe] built from source, tailored to the target, so its modules are a few megabytes rather than a hundred-plus. This part of the gap isn't really "Debian vs Alpine" — it's "stock distribution kernel vs tailored build," and a production Debian image on [yoe] can swap in a tailored kernel too. Out of the box, though, the distro kernel brings everything.

The userland. The remainder is the platform itself: glibc and its multiarch libraries, systemd and NetworkManager, the full apt and dpkg stack, complete coreutils instead of busybox applets, locales, udev rules. musl plus busybox plus OpenRC is simply a lighter foundation, and on a device that difference compounds.

Size isn't the only difference — assembly is heavier too

The two images are also assembled differently, and it comes down to what a package does when it installs.

Assembling the Alpine image is essentially one step: apk extracts the packages into the root filesystem, resolves their dependencies, and checks for file conflicts. Alpine packages are largely self-contained — the install-time logic is minimal, mostly busybox wiring up its own applet symlinks. Few moving parts, and it's fast.

A Debian .deb carries maintainer scripts — preinst, postinst — that have to run to finish the install: creating users, enabling systemd services, running ldconfig, registering alternatives. So [yoe] assembles the Debian rootfs with mmdebstrap driving apt and dpkg, then runs every package's scripts to reach a fully configured state. And because those scripts assume a complete base system is already in place, assembly carries ordering subtleties the Alpine path never hits. A concrete one: openssh-server's post-install reaches for awk before the package that provides it has been configured, so the assembler pre-stages the awk alternative ahead of time to keep the script from failing. For a foreign architecture, all of those scripts run under QEMU emulation as well.

None of this is a knock on Debian — that maintainer-script model is exactly what makes the broad apt ecosystem drop in and just work, users and services configured the way the package author intended. It's the same tradeoff as the size: the richness that earns Debian its place is also what makes it heavier to assemble. Alpine does less at install time, so there's less to do at build time.

It shows up on the clock, too. With every dependency package already built and cached — so the timer captures only the image-assembly step, not the source builds behind it — reassembling the dev image (a working image with editors and diagnostics, a notch up from the minimal one measured above) on the same qemu-x86_64 target takes about 10 seconds on Alpine and roughly 100 on Debian: close to a 10× gap. Alpine's side is a single apk extract; Debian's is mmdebstrap plus dpkg configuring every package and running its maintainer scripts, under QEMU for a foreign architecture. The Debian time also wanders more from run to run (90–120 s), because it leans on apt and dpkg doing real work rather than a near-deterministic unpack.

Where it stands

Debian support is experimental but real: the image measured above boots and accepts SSH, so it's a device you can log into and work on, not a paper target. The build path is solid and the size numbers are measurements, not estimates. There's still plenty to harden, and honest comparisons — like this one — are how we keep the tradeoffs in view as it matures.

What's next

Hardening the Debian path from experimental toward production — tailoring the kernel down from the stock one, and proving it out across more targets. The Videos page has the full walkthrough set.

If you have a workload that needs glibc, we'd love to hear how it goes — open a discussion or send a note. To follow [yoe] as it grows, star and watch the repo and subscribe for updates — there's an email signup at the foot of every page, too.

Cliff Brake June 04, 2026 #embedded #linux #yocto #platform #video #containers #dependencies #size