Model or dataset
NetBSDfr/smolBSD avatar
NetBSDfr/smolBSD

smolBSD: building a NetBSD microvm from a SMOLerfile or a bmake target

smolBSD is a tiny BSD UNIX (NetBSD) system creation tool, primarily aimed at building modern, lightweight, fast micro VMs

725 stars54 forksShellBSD-2-Clause

At a glance

What is it?
smolBSD assembles a minimal NetBSD system as a microvm that boots in about ten milliseconds, and it does so without a NetBSD installation on the build host. Images come from a Dockerfile-like SMOLerfile through a wrapper script, or from bmake targets and a raw image file, with QEMU and Firecracker as the hypervisors.
Who is it for?
smolBSD fits an engineer who wants a per service NetBSD microvm with a small footprint and a fast boot, and who is comfortable with make(1) style configuration and NetBSD sets. It does not fit a team that needs a reproducible cross platform artifact pipeline without a Unix build host, since the toolchain list is long and a few utilities are missing on macOS.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A microvm built from NetBSD sets, with no NetBSD install on the host

smolBSD is described as a tiny BSD UNIX system creation tool, primarily aimed at building modern, lightweight, fast micro VMs, and it produces a minimal NetBSD based machine that can boot and start a service in a couple of milliseconds. The point that makes it usable in CI or on a laptop is that no prior NetBSD installation is required: a microvm can be created and started from any NetBSD, GNU/Linux or macOS system, and probably more. The boot path is PVH, and the README claims NetBSD/amd64 and NetBSD/i386 can boot QEMU or Firecracker in about 10 milliseconds on mid-end x86 CPUs from 2025. The project is mostly shell, and the top level listing shows the pieces: mkimg.sh for image creation, startnb.sh for launching the machine, smoler.sh as the higher level wrapper, plus sets, pkgs, service, smolerfiles and kernel directories.

Two workflows, and the difference is where the control lives

The README puts the two ways to build and run side by side, and the contrast is the fastest way to understand the project. The smoler.sh path is Docker shaped: you build from a SMOLerfile and you run a tagged image name such as foo-amd64:latest stored in the images directory. The bmake path is manual: you build with a service target and you run startnb.sh against a raw file such as images/foo-amd64.img. Under the hood smoler.sh still calls mkimg.sh to build and startnb.sh to run, and it manages a local image registry with build, run, push and pull on top. The README's advice is to pick the Docker style wrapper if you are familiar with Docker, and the low level launcher when you want direct control over QEMU flags, a custom configuration file passed with -f, or when you are building services by hand with bmake.

A service is the unit of build, and it needs an etc/rc to do anything

Everything is organised around a service directory, which is the base unit that holds the pieces needed to build a BSD system from scratch. Its layout is fixed: a base directory with an etc/rc file, an optional postinst directory whose scripts run at the end of root filesystem preparation, an options.mk for service specific defaults and an own.mk for personal overrides that are not committed to the repository, a common directory whose scripts are bundled into the microvm's /etc/include, and a rescue directory. Two of those rules are worth internalising. A postinst script is executed by the build host at build time, so anything it does is not part of the running system. An etc/rc file is mandatory when standard NetBSD init(8) is used, and it is executed by the microvm itself, defining what starts at boot. Common scripts are the natural place for shared boot logic, and the README shows the basicrc pattern of setting PATH, umask and mounting filesystems.

The SMOLerfile reuses the Dockerfile verbs, with NetBSD sets as the base

The SMOLerfile format exists for people who already think in Dockerfiles, and the README is candid that it does not implement the whole Dockerfile reference, only the well known verbs. FROM is followed by NetBSD sets rather than an image, and you probably want at least base and etc, with the option of shipping only part of a set by appending a tar-like glob, for example comp:/usr/bin/strip. The smolbsd.service LABEL is mandatory and sets the service name, while ARG values can be overridden with --build-arg. The example service file in the repository looks like this.

sh
$ cat smolerfiles/Dockerfile.myservice
FROM base,etc

LABEL smolbsd.service=myservice

CMD ksh

A fuller example in the README adds image minimisation, a publish label for port mapping, and a package installation step.

dockerfile
FROM base,etc

LABEL smolbsd.service=caddy
# Optional image minimization to actual content
LABEL smolbsd.minimize=y
# Dockerfile doesn't support port mapping
LABEL smolbsd.publish="8881:8880"

RUN pkgin up && pkgin -y in caddy

EXPOSE 8880

Building and running that service is three commands, and the last one is the check that the machine actually answers.

sh
host$ ./smoler.sh build smolerfiles/Dockerfile.caddy
sh
host$ ./startnb.sh -f etc/caddy.conf
sh
host$ curl -I 127.0.0.1:8881

The dependency list is long, and macOS misses a few tools

The requirements are a GNU/Linux, NetBSD or macOS host, with a VT-capable x86 CPU or an ARM64 CPU recommended, since other systems might work but without CPU acceleration. The tool list includes curl, git, bmake on Linux and macOS or make on NetBSD, the QEMU binary matching the destination architecture, sudo or doas, uuidgen, nm, bsdtar on Linux, sgdisk on Linux for GPT boot, lsof, jq for smoler.sh, and optionally socat for the control socket and picocom for console workloads. The README also flags that nm is not used or functional on macOS. The two install lines are copy and paste ready, one for Debian and derivatives and one for Homebrew.

sh
$ sudo apt install curl git bmake qemu-system-x86_64 uuid-runtime binutils libarchive-tools gdisk socat jq lsof picocom
sh
$ brew install curl git bmake qemu binutils libarchive socat jq lsof picocom

Note the difference between the two: the Debian line pulls uuid-runtime, gdisk and libarchive-tools, which on macOS are covered differently or not at all by the Homebrew set, and that is where you will hit friction first.

Image size and package versions are decided in options.mk

Service specific defaults live in options.mk, written in make(1) format, and the README example shows exactly the two knobs you are most likely to touch: the size of the resulting image in megabytes, and the package version to use. The latter is not cosmetic. The Makefile in the repository root defaults to NetBSD 11 packages, and the example options.mk notes that as of October 2025 there are no NetBSD 11 packages for architectures other than amd64, so a non-amd64 build has to pin the older package set explicitly.

sh
$ cat service/nbakery/options.mk
# size of resulting inage in megabytes
IMGSIZE=1024
# as of 202510, there's no NetBSD 11 packages for !amd64
.if defined(ARCH) && ${ARCH} != "amd64"
PKGVERS=10.1
.endif

The Makefile also resolves the kernel and the live image for the host architecture, picks the sets directory per architecture, and can enable a BIOS boot path with a separate netbsd-GENERIC kernel, which is the fallback for machines where the faster path is unavailable. The defaults for the build itself are two CPUs and 1024 megabytes of memory.

A young project with a moving NetBSD base and a permissive licence

The licence is BSD-2-Clause, which is permissive enough for commercial use without notice obligations beyond keeping the licence text, and the project publishes prebuilt compressed images under a release tagged latest, dated 2025-10-06. The Makefile carries a version comment of v0.6.0, and it points at NetBSD daily builds rather than a fixed release, with the amd64 live image taken from the 11.99.5 daily snapshot. That choice keeps the base current but also means a build is not reproducible over time: the same service definition can pull a different base set tomorrow. The last push was on 2026-10-19, so the scripts and the NetBSD dependency move together, and that is the trade you accept when you build images from daily sets rather than pinned release archives.

Editorial conclusion

smolBSD fits an engineer who wants a per service NetBSD microvm with a small footprint and a fast boot, and who is comfortable with make(1) style configuration and NetBSD sets. It does not fit a team that needs a reproducible cross platform artifact pipeline without a Unix build host, since the toolchain list is long and a few utilities are missing on macOS. Before you build on it, read the service layout and decide where your rc scripts live, because a service without an etc/rc has no boot behaviour, and check the pkgvers handling in the Makefile, since the NetBSD 11 package set is not available for every architecture.

Frequently asked questions

Do I need NetBSD installed to build a smolBSD microvm?

No. The README states that no prior NetBSD installation is required, and that a microvm can be created and started from any NetBSD, GNU/Linux or macOS system. The build host needs a set of Unix tools, including bmake or make, QEMU, bsdtar, uuidgen and jq.

What is the difference between smoler.sh and bmake in smolBSD?

smoler.sh is the Docker style wrapper: you build from a SMOLerfile and run a tagged image name, and it manages a local registry with build, run, push and pull. The bmake path builds a service target and runs startnb.sh against a raw image file, which is the route to use when you want direct control over QEMU flags or a custom config file.

What must a smolBSD service directory contain to boot?

An etc/rc file is mandatory when standard NetBSD init(8) is used, because it defines what starts at boot and it runs inside the microvm. Optional pieces are a postinst script, which runs on the build host at build time rather than in the guest, an options.mk for service defaults, and an own.mk for local overrides that are not committed.

Official sources

  1. License: BSD-2-Clause
  2. NetBSDfr/smolBSD on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/netbsdfr-smolbsd.svg)](https://hysenlabs.com/projects/netbsdfr-smolbsd)

Was this useful?