NixNG
NixNG is a Linux distribution currently under development, derived
from NixOS. It is being positioned as a lightweight alternative to
NixOS, specifically targeting container environments.
The project achieves its reduced size by omitting systemd from
NixOS and minimizing the default package set. Since NixOS container
images are a bit heavy, a lighter alternative is definitely welcome.
Dropping systemd also opens up possibilities for using
lighter-weight init systems like runit, which I find to be an exciting
prospect.
But just how much smaller is NixNG in practice, compared to an image
based on the original NixOS? I created both images to compare their
sizes.
The experiment
The official Nix image is available on DockerHub. I built
a comparable NixNG image that includes only the Nix package manager and
then compared the sizes of the two.
| Distro | Package | Base image/Build |
|---|---|---|
| Official Nix | Nix 2.32.2 | DockerHub nixos/nix:2.32.2
|
| NixNG | Nix 2.32.2 | Built using the method below |
I ensured that the platform was consistent: x86_64-linux.
NixNG build flake setup
I set up a minimal flake project for the test.
flake.nix:
{
inputs = {
nixng.url = "github:nix-community/NixNG";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs =
{
self,
nixng,
nixpkgs,
...
}:
{
examples.nixng-nix = import ./examples/nixng-nix.nix {
inherit (nixng) nglib;
inherit nixpkgs;
system = "x86_64-linux";
};
};
}
The system of interest for comparison is defined in
examples.nixng-nix, based on
an example from the NixNG repository:
examples/nixng-nix.nix:
{
nglib,
nixpkgs,
system,
}:
nglib.makeSystem {
inherit nixpkgs;
inherit system;
name = "nixng-nix";
config =
{ pkgs, ... }:
{
dumb-init = {
enable = true;
type.shell = { };
};
nix = {
enable = true;
package = pkgs.nixVersions.nix_2_32;
config = {
experimental-features = [
"nix-command"
"flakes"
];
sandbox = false;
};
};
};
}
Build and load the OCI image
I generated and loaded the Docker image tar file:
$ docker run --rm --platform linux/amd64 -v $(pwd):/work -w /work \
nixos/nix:2.32.2 bash -c '
{
echo "filter-syscalls = false"
echo "experimental-features = nix-command flakes"
} >> /etc/nix/nix.conf
nix build .#examples.nixng-nix.config.system.build.ociImage.stream
./result > nixng-nix-image.tar
'
$ docker image load -i nixng-nix-image.tar
Note: Since I use Docker Desktop on an ARM Mac, I
had to add filter-syscalls = false to the Nix configuration
to avoid an error during the build.
Results
Image sizes
With the official Nix image already available, I checked the sizes:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nixos/nix 2.32.2 f9b3c7811e27 55 years ago 436MB
nixos/nix latest f9b3c7811e27 55 years ago 436MB
nixng-nix latest 26361447b07f 55 years ago 356MB
The official image was 436MB, while the NixNG image came in
at 356MB. That's a size reduction of 80MB (approximately 18%).
/nix/store/ contents
I was curious to see exactly which packages were omitted.
First, I looked at the package count in the /nix/store/ directory:
$ docker run --platform linux/amd64 nixos/nix:2.32.2 \
sh -c 'ls /nix/store' 2>/dev/null | rg '^[a-z0-9]+-' | wc -l
121
$ docker run --platform linux/amd64 nixng-nix \
sh -c 'ls /nix/store' 2>/dev/null | rg '^[a-z0-9]+-' | wc -l
81
The official Nix image contains 121 packages, compared to 81
in NixNG—a reduction of 40 packages.
Next, I looked at the detailed differences. After preprocessing the
package names to normalize version and date differences:
$ docker run --platform linux/amd64 nixos/nix:2.32.2 \
sh -c 'ls /nix/store' 2>/dev/null | rg '^[a-z0-9]+-' \
| cut -d'-' -f2- \
| sed -Ee 's#[0-9]{4}(-?[0-9]{2}(-?[0-9]{2})?)?[a-z]?#DATE#' \
-e 's#[0-9]+\.[0-9]+([.p-][0-9]+)?#VERSION#' \
| sort \
| uniq \
> nixos-nix-nix-store.txt
$ docker run --platform linux/amd64 nixng-nix \
sh -c 'ls /nix/store' 2>/dev/null | rg '^[a-z0-9]+-' \
| cut -d'-' -f2- \
| sed -Ee 's#[0-9]{4}(-?[0-9]{2}(-?[0-9]{2})?)?[a-z]?#DATE#' \
-e 's#[0-9]+\.[0-9]+([.p-][0-9]+)?#VERSION#' \
| sort \
| uniq \
> nixng-nix-nix-store.txt
Comparing the diff reveals the omitted components:
--- nixos-nix-nix-store.txt 2025-11-08 21:45:41
+++ nixng-nix-nix-store.txt 2025-11-08 21:45:48
@@ -1,6 +1,5 @@
acl-VERSION
attr-VERSION
-audit-VERSION-lib
aws-c-auth-VERSION
aws-c-cal-VERSION
aws-c-common-VERSION
@@ -14,73 +13,45 @@
aws-checksums-VERSION
aws-crt-cpp-VERSION
aws-sdk-cpp-VERSION
-base-system
bash-interactive-VERSION
-bash-interactive-VERSION-man
bash-VERSION
boehm-gc-VERSION
boost-VERSION
brotli-VERSION-lib
busybox-VERSION
bzip2-VERSION
-channel-nixos
-coreutils-full-VERSION
-coreutils-VERSION
+ca-certificates.crt
curl-VERSION
-curl-VERSION-bin
-curl-VERSION-man
-db-VERSION
-dns-root-data-DATE
-editline-VERSION
-expat-VERSION
-findutils-VERSION
+dumb-init-VERSION
+editline-VERSION-unstable-DATE
gcc-VERSION-lib
gcc-VERSION-libgcc
-gdbm-VERSION-lib
-gettext-VERSION
-git-minimal-VERSION
+generate-shadow
glibc-VERSION
-glibc-VERSION-bin
-gmp-with-cxx-VERSION
-gnugrep-VERSION
-gnused-VERSION
-gnutar-VERSION
-groff-VERSION
-gzip-VERSION
-gzip-VERSION-man
+group
+hwloc-VERSION-lib
iana-etc-DATE
+icu4c-VERSION
keyutils-VERSION-lib
krb5-VERSION-lib
-ldns-VERSION
-less-668
-less-668-man
libarchive-VERSION-lib
libblake3-VERSION
-libbsd-VERSION
-libcap-ng-VERSION
-libcap-VERSION-lib
-libcbor-VERSION
libcpuid-VERSION
-libedit-DATE-VERSION
-libfido2-VERSION
libgit2-VERSION-lib
libidn2-VERSION
-libmd-VERSION
-libpipeline-VERSION
libpsl-VERSION
libseccomp-VERSION-lib
libsodium-VERSION
libssh2-VERSION
libunistring-VERSION
-libxcrypt-VERSION
libxml2-VERSION
-linux-pam-VERSION
llhttp-VERSION
lowdown-VERSION-lib
-man-db-VERSION
-manifest.nix
ncurses-VERSION
+ndig4f4dx8bmrmyr5vfm19g02r9l9ggm-source
nghttp2-VERSION-lib
+nghttp3-VERSION
+ngtcp2-VERSION
nix-cmd-VERSION
nix-expr-VERSION
nix-fetchers-VERSION
@@ -89,32 +60,20 @@
nix-store-VERSION
nix-util-VERSION
nix-VERSION
-nss-cacert-VERSION
-openssh-VERSION
+nix.conf
+nixng-nixng-nix
+onetbb-DATE.VERSION
openssl-VERSION
+passwd
pcre2-VERSION
-pcsclite-VERSION-lib
+profile
publicsuffix-list-0-unstable-DATE
readline-VERSION
-root-profile-env
s2n-tls-VERSION
-shadow-VERSION
-source
+service-dir
sqlite-VERSION
-systemd-minimal-libs-VERSION
-tbb-DATE.VERSION
-tbb-DATE.VERSION-dev
-tcb-VERSION
-util-linux-minimal-VERSION-bin
-util-linux-minimal-VERSION-lib
-util-linux-minimal-VERSION-login
-util-linux-minimal-VERSION-mount
-util-linux-minimal-VERSION-swap
-wget-VERSION
-which-VERSION
+tzdata-DATE
xgcc-VERSION-libgcc
xz-VERSION
-zlib-ng-VERSION
zlib-VERSION
zstd-VERSION
-zstd-VERSION-bin
In addition to the removal of systemd (systemd-minimal-libs),
in NixNG, many other packages have also been omitted.
Final thoughts
To be blunt, the default advice for minimizing container size is
often: "Use Alpine or Distroless!"
However, if committed to using Nix in a project and want to
save a bit on cloud storage or bandwidth costs, NixNG should be
a viable option.
Translated from the original post
at https://m15a.dev/ja/posts/nixng-image-size/.
Top comments (0)