{"slug": "visualizing-nix-closures", "title": "Visualizing Nix closures", "summary": "A developer built seenix.dev, a single-page browser tool that lays out every byte of a Nix closure on a Hilbert-curve map at one pixel per byte, letting users zoom from a full NixOS system down to the hex of libc.so.6. The tool renders a GNOME desktop closure of 1,324 store paths and 5.3 GiB in 3 ms using only narinfos, with no NAR downloads and no server. Visualizing the remarshal binary's closure showed 41 store paths and 234 MiB with no ffmpeg and no ruby, contradicting a trending X thread that claimed the Python binary included those packages.", "body_md": "**tl;dr** [seenix.dev](https://seenix.dev/) lays every byte of a Nix closure out on a map, one pixel per byte, and lets you zoom from a whole NixOS system down to the hex of `libc.so.6`. Try [hello](https://seenix.dev/?path=/nix/store/xl1h9i29pgq2q5cszjhm5wpfxfbbqwyi-hello-2.12.3), [firefox](https://seenix.dev/?path=/nix/store/5l9n8bw1wifj5kdr8gzlrkk1b510dfiv-firefox-155.0.1) or [a GNOME desktop](https://seenix.dev/?path=/nix/store/5ryb0d1a261bgvxqqd436yx8i7j44qlc-nixos-system-nixos-26.11pre1074086.efe6f071ede9&mode=package). Nothing runs on a server.\n\nWith the advent of LLMs I keep tugging at any *crazy* question I ask myself. I know there is the *anti-AI* crowd and they will happily proclaim anything pursued in this vein as “slop” but I am feeling fortunate to be able to explore these questions.\n\nMy recent *itch* was to ask “what does a Nix closure look like?” and to answer it in a way that is *interactive* and *visual*. I wanted to see the bytes, not just the store paths. I had come across [binvis.io](https://binvis.io) on Hacker News and I found it a compelling way to look at data. I personally never found a need for it, but I found it fascinating none-the-less.<sup>1</sup>1Aldo Cortesi’s [writing on visualising binaries](https://corte.si/posts/visualisation/binvis/) is a great resource on this. \n\nThe timing for this itch was perfect. I noticed a trending thread on [X](https://x.com/HSVSphere/status/2045193277977100772?s=20) where a Python binary seemingly includes `ffmpeg` and `ruby`. 🤷\n\nI built that tool. You can check it out at [seenix.dev](https://seenix.dev/). It is a single-page web app that runs entirely in your browser, with no server. It fetches the narinfos of a closure and lays them out on a map, one pixel per byte, and lets you zoom in to see the bytes themselves.\n\nWe can visualize the closure of that binary, `remarshal`, and see if it really does include those two packages. Turns out it does not. The closure is 41 store paths and 234 MiB, with no `ffmpeg` and no `ruby` among them. Turns out those dependencies are build-time and are not included in the final runtime closure.\n\nWe can visualize much larger closures. Here is a GNOME desktop: 1,324 store paths and 5.3 GiB, each colour one package.\n\nThat picture needed zero NAR downloads. It was laid out in 3 ms from the narinfos alone. 🤯\n\n# [§](#one-byte-one-pixel)One byte, one pixel\n\nThe “trick” I learned to make this visualization possible, is the [Hilbert curve](https://en.wikipedia.org/wiki/Hilbert_curve). A Hilbert curve is a single, unbroken line that folds back and forth such that it completely fills up a flat square. **It is a fractal**.\n\nEvery store path in the closure is sorted by name (the root first) and their NARs are concatenated into one long line of bytes. The Hilbert curve folds that line into a square, so byte *n* is pixel *n* along the curve.\n\nThe Hilbert curve has two properties that lend itself nicely to visualize binaries and as a result Nix closures:\n\n**Bytes that are near each other in a file stay near each other on the map.** A NAR is a single contiguous range of bytes, so a store path is a single contiguous region on the map. A file inside that store path is a smaller contiguous region, and a section inside that file is smaller still and so forth.\n\n**Squares are just byte ranges.** Here’s a tiny 4×4 map. Each number is the byte that lands on that pixel:\n\n```\n 0   1  14  15\n 3   2  13  12\n 4   7   8  11\n 5   6   9  10\n```\n\nThat means we can easily place a store path on the map by knowing its starting byte and its size. That’s what makes the map cheap to draw.<sup>2</sup>2This is why the world is always a power of four bytes. hello’s closure is 36 MiB, which fills a bit over half of a 64 MiB square, and the rest is drawn as background. \n\nThe layout only needs each path’s `NarSize`, which every narinfo carries, so the whole map exists before a single NAR is downloaded. Hovering already tells you which store path you are pointing at, its size, its *retained size* (the bytes that would leave the closure without it) and a “why is this here” chain back to the root.\n\n# [§](#zoom-and-enhance)Zoom and enhance\n\nAs you zoom in, the NARs on screen are fetched from the cache and the color fills in. Here is `hello`’s closure, most of which is glibc:\n\nBlue is printable ASCII, red is high bytes, green is control bytes and black is `0x00`. The speckled top is machine code. The big solid blue area at the bottom is glibc’s locale data, which is plain text.\n\nKeep zooming and every pixel becomes a byte you can read. Hovering names the file inside the NAR, and for ELF files, the section.\n\nThat is `.text` of `libc.so.6`, in your browser tab, fetched from [cache.nixos.org](https://cache.nixos.org), **without any server**. 😈\n\n# [§](#why-though)Why though?\n\nDoes everything need a purpose? Sometimes something is fun to make and to use with no real purpose.\n\nFor fun, I even added a Save PNG button, and it saves the view at the canvas’s full resolution. The ultimate ricing of your NixOS system: a pixel image of your desktop closure. Can [Omarchy](https://omarchy.com/) do that? 😎\n\nAnything you can export works:\n\n``` bash\n$ nix path-info -r --json /run/current-system > closure.json\n```\n\nDrop the file and see the map. You can provide additional Nix binary caches to fetch NARs from as well.\n\nThe source is at [github.com/fzakaria/seenix](https://github.com/fzakaria/seenix). [Go look at something big.](https://seenix.dev/?path=/nix/store/5ryb0d1a261bgvxqqd436yx8i7j44qlc-nixos-system-nixos-26.11pre1074086.efe6f071ede9&mode=package)\n\nBuild without purpose. Have fun.", "url": "https://wpnews.pro/news/visualizing-nix-closures", "canonical_source": "https://fzakaria.com/2026/09/15/visualizing-nix-closures", "published_at": "2026-09-16 03:00:00+00:00", "updated_at": "2026-09-16 03:38:07.166541+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["seenix.dev", "Nix", "NixOS", "libc.so.6", "remarshal", "ffmpeg", "ruby", "GNOME"], "alternates": {"html": "https://wpnews.pro/news/visualizing-nix-closures", "markdown": "https://wpnews.pro/news/visualizing-nix-closures.md", "text": "https://wpnews.pro/news/visualizing-nix-closures.txt", "jsonld": "https://wpnews.pro/news/visualizing-nix-closures.jsonld"}}