{"article":{"slug":"every-package-is-already-installed","title":"Every package is already installed","subtitle":null,"summary":"Farid Zakaria introduces omnibin: a FUSE filesystem that puts every binary Nixpkgs ever shipped on your $PATH—nothing installed upfront, 0 bytes on disk until something is actually run.","content_type":"blog_post","language":"en","canonical_url":"https://fzakaria.com/2026/09/24/every-package-is-already-installed","author":{"name":"Farid Zakaria","url":"https://fzakaria.com/","person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"fzakaria.com","url":"https://fzakaria.com/","listing_slug":null,"listing":null},"topics":[{"name":"Open Source","slug":"open-source","url":"https://listedarticles.com/topics/open-source"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Infrastructure","slug":"infrastructure","url":"https://listedarticles.com/topics/infrastructure"},{"name":"Linux","slug":"linux","url":"https://listedarticles.com/topics/linux"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1001,"reading_minutes":4,"published_at":"2026-09-24T12:00:00.000Z","added_at":"2026-09-25T18:11:13.861Z","updated_at":"2026-09-25T18:11:13.861Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":false},"profile_url":"https://listedarticles.com/articles/every-package-is-already-installed","markdown_url":"https://listedarticles.com/articles/every-package-is-already-installed.md","example":false,"citation":"Farid Zakaria, fzakaria.com. \"Every package is already installed.\" 24 Sept 2026. https://fzakaria.com/2026/09/24/every-package-is-already-installed (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://fzakaria.com/2026/09/24/every-package-is-already-installed"},"body_markdown":"**tl;dr;** omnibin is a FUSE filesystem that puts **every binary nixpkgs ever shipped** on your `$PATH`. Nothing is installed. Nothing needs building. 0 bytes on disk until something actually reads a file. 😈\n\n\nIt’s 2026, why am I still installing packages individually?<sup>1</sup>1Yes, I am a little inspired after watching DHH’s keynote at RailsConf 2026. I feel the same way about package management. \n\nWhy must I go through the ritual of adding a package to my `configuration.nix`, running `nix-shell` or succumb to the hellscape of `nix-env -iA`.\n\nNix gives us the power of having packages installed side-by-side without conflict. Why do I have to pick which ones I want to install?\n\nWhy can’t I just have them all?\n\nWhat if the machine just had all of them?\n\n```\n$ nix run github:fzakaria/omnibin\nomnibin: tree at /run/user/1000/omnibin, cache at /home/you/.cache/omnibin\n$ ls /omnibin/bin | wc -l\n51468\n$ python3 --version\nPython 3.14.6\n$ python3@3.6.2 --version\nPython 3.6.2\n```\nThat is __over fifty thousand__<sup>2</sup>2There are actually 881,933 binaries in the tree, but `ls /omnibin/bin` only lists the latest version of each binary. The versioned forms are still available, but they are not listed.  top-level binaries available on my `$PATH`, from 2013 to 2026 built by Nixpkgs, available on-demand, without installing anything.\n\nThis is the magic 🧙♂️ of Nix, but it’s not restricted to Nix.\n\nEveryone seems to still love Docker and OCI, why am I still picking which base image to use? Why can’t I just have them all?\n\n```\n# syntax=docker/dockerfile:1\nFROM fmzakari/omnibin:latest\nCOPY <<'SH' /demo.sh\npython3@3.6.2 -c 'import sys; print(sys.version.split()[0])'\njq --version\ngcc@10.2.0 --version | head -1\nSH\nCMD [\"bash\", \"/demo.sh\"]\n```\nIs this the ultimate agent harness? It’s a container with everything in it, right from the start. Try it at fmzakari/omnibin.\n\n```\n$ docker build -t example .\n$ docker run --rm --device /dev/fuse --cap-add SYS_ADMIN example\n3.6.2\njq-1.8.1\ngcc (GCC) 10.2.0\n```\nOf course, I cannot forget our NixOS friends. You no longer have to curate your `environment.systemPackages` or `home.packages`, you can just have them all.\n\n```\n{\n  imports = [ inputs.omnibin.nixosModules.default ];\n  services.omnibin.enable = true;\n}\n```\nWhat is “package management” if every package is already installed?\n\n## §What is this sorcery?\n\nTurns out that Hydra writes a `.ls` file next to every single narinfo on cache.nixos.org that describes the contents of the archive as JSON:\n\n```\n$ curl -s --compressed https://cache.nixos.org/3n4qphl9s728sz8frmpqqrv9b1m87g68.ls | jq\n{\n  \"root\": {\n    \"entries\": {\n      \"bin\": {\n        \"entries\": {\n          \"python3\": { \"target\": \"python3.14\", \"type\": \"symlink\" },\n          \"python3.14\": { \"executable\": true, \"size\": 14264, \"type\": \"regular\" }\n```\nThat metadata turns out to be the perfect index for a FUSE filesystem that can lazily fetch the NARs from the cache and unpack them on-demand. 🤓\n\nNone of this would mean anything without nixpkgs-multiverse, which already resolves any `(attribute, version)` in nixpkgs history to the store path Hydra built for it on cache.nixos.org.\n\nWhen you combine the two, you get a filesystem that can answer the question “where is `python3@3.6.2`” and then fetch it from the cache and unpack it for you, all without ever having to install it.\n\nI crawled all of it the `.ls` files in under twelve minutes. 🤯\n\nOnce you have that, the filesystem writes itself:\n\n```\n$ ls /nix/store/2lb6nn8ivk1alhckv43n7734lqwbw7h9-python3-3.6.2/bin\n2to3      idle     pydoc     python   python3.6         python3-config  pyvenv\n2to3-3.6  idle3    pydoc3    python3  python3.6-config  python-config   pyvenv-3.6\n          idle3.6  pydoc3.6           python3.6m        python3.6m-config\n```\nThat is CPython 3.6.2, from 2017. That `ls` *downloaded nothing*, it is answered from the pre-crawled index.\n\n## §Do not `ls` the tree\n\nAgents are “a thing”. Making them useful is a thing. Making them useful without installing anything is a thing.\n\nIf your agent tried to `ls /omnibin/bin` and stat every single entry, it would have a really bad time. There are 881,933 binaries in the tree, and it would take a long time to stat them all.\n\nTo help the agents out a bit, `ls /omnibin/bin` lists only the bare names, one per executable, each resolving to the newest package that provides it.\n\nThe versioned forms all resolve, but they are not listed. For example, `python3` resolves to the latest Python 3, which is 3.14.6 at the time of writing, but `python3@3.6.2` resolves to the 2017 version.\n\nFor everything else there is the index, which is sitting right there in the mount:\n\n```\n$ sqlite3 /omnibin/index.db \\\n    \"SELECT attr, version\n    FROM bins\n    WHERE name = 'python3'\n    ORDER BY version\"\n```\nThat UX is a little rough, so you can also use the `omnibin` CLI to query the index:\n\n```\n$ omnibin which python3\n/nix/store/gxzhl7aaiid7zp3y47jqqiq7zg5mqpwp-python3-3.14.6/bin/python3\n$ omnibin which --all python3 | wc -l\n610\n$ omnibin which --all ffmpeg | head -2\nffmpeg@3.1.7  ffmpeg  0.4 MB  /nix/store/0adpc3…-ffmpeg-3.1.7-bin/bin/ffmpeg\nffmpeg@3.2.4  ffmpeg  0.4 MB  /nix/store/nhfgdv…-ffmpeg-3.2.4-bin/bin/ffmpeg\n```\nLastly, there is a /omnibin/README.md whose entire job is to tell whatever is exploring the filesystem to stop exploring the filesystem and query the database instead. 🤖\n\n## §What’s the catch?\n\nAt this point it should be obvious, but you pay for this on startup for the first access.\n\n```\n$ time python3@3.6.2 -c 'import sys; print(sys.version.split()[0])'\n3.6.2\nreal    0m2.690s\n$ time python3@3.6.2 -c 'print(6*7)'\n42\nreal    0m0.035s\n```\nThe first run took 2.7 seconds to fetch the NARs and unpack them, the second run was instantaneous because the store paths were already present.\n\nOther than that? Not really, which is pretty amazing.\n\nFor any long-lived machine, you would expect your `/nix/store` to already be warmed up with the packages you need, so the first access penalty is not a big deal.\n\nI remember one of the first things that blew my mind and sold me on Nix, was seeing a demo by @burke on comma. The capability to test a package, at a single nixpkgs revision, without “installing it”; revolutionary! I believe this to be a spiritual successor and I hope to imbue others with the same sense of wonder and amazement that I felt back then as a beacon of the power of Nix.\n\nThe repo is at github.com/fzakaria/omnibin.\n\nPlease `ls` responsibly.","body_html":"<p><strong>tl;dr;</strong> omnibin is a FUSE filesystem that puts <strong>every binary nixpkgs ever shipped</strong> on your <code>$PATH</code>. Nothing is installed. Nothing needs building. 0 bytes on disk until something actually reads a file. 😈</p>\n<p>It’s 2026, why am I still installing packages individually?&lt;sup&gt;1&lt;/sup&gt;1Yes, I am a little inspired after watching DHH’s keynote at RailsConf 2026. I feel the same way about package management. </p>\n<p>Why must I go through the ritual of adding a package to my <code>configuration.nix</code>, running <code>nix-shell</code> or succumb to the hellscape of <code>nix-env -iA</code>.</p>\n<p>Nix gives us the power of having packages installed side-by-side without conflict. Why do I have to pick which ones I want to install?</p>\n<p>Why can’t I just have them all?</p>\n<p>What if the machine just had all of them?</p>\n<pre><code>$ nix run github:fzakaria/omnibin\nomnibin: tree at /run/user/1000/omnibin, cache at /home/you/.cache/omnibin\n$ ls /omnibin/bin | wc -l\n51468\n$ python3 --version\nPython 3.14.6\n$ python3@3.6.2 --version\nPython 3.6.2</code></pre>\n<p>That is <strong>over fifty thousand</strong>&lt;sup&gt;2&lt;/sup&gt;2There are actually 881,933 binaries in the tree, but <code>ls /omnibin/bin</code> only lists the latest version of each binary. The versioned forms are still available, but they are not listed.  top-level binaries available on my <code>$PATH</code>, from 2013 to 2026 built by Nixpkgs, available on-demand, without installing anything.</p>\n<p>This is the magic 🧙♂️ of Nix, but it’s not restricted to Nix.</p>\n<p>Everyone seems to still love Docker and OCI, why am I still picking which base image to use? Why can’t I just have them all?</p>\n<pre><code># syntax=docker/dockerfile:1\nFROM fmzakari/omnibin:latest\nCOPY &lt;&lt;&#39;SH&#39; /demo.sh\npython3@3.6.2 -c &#39;import sys; print(sys.version.split()[0])&#39;\njq --version\ngcc@10.2.0 --version | head -1\nSH\nCMD [&quot;bash&quot;, &quot;/demo.sh&quot;]</code></pre>\n<p>Is this the ultimate agent harness? It’s a container with everything in it, right from the start. Try it at fmzakari/omnibin.</p>\n<pre><code>$ docker build -t example .\n$ docker run --rm --device /dev/fuse --cap-add SYS_ADMIN example\n3.6.2\njq-1.8.1\ngcc (GCC) 10.2.0</code></pre>\n<p>Of course, I cannot forget our NixOS friends. You no longer have to curate your <code>environment.systemPackages</code> or <code>home.packages</code>, you can just have them all.</p>\n<pre><code>{\n  imports = [ inputs.omnibin.nixosModules.default ];\n  services.omnibin.enable = true;\n}</code></pre>\n<p>What is “package management” if every package is already installed?</p>\n<h2 id=\"what-is-this-sorcery\">§What is this sorcery?</h2>\n<p>Turns out that Hydra writes a <code>.ls</code> file next to every single narinfo on cache.nixos.org that describes the contents of the archive as JSON:</p>\n<pre><code>$ curl -s --compressed https://cache.nixos.org/3n4qphl9s728sz8frmpqqrv9b1m87g68.ls | jq\n{\n  &quot;root&quot;: {\n    &quot;entries&quot;: {\n      &quot;bin&quot;: {\n        &quot;entries&quot;: {\n          &quot;python3&quot;: { &quot;target&quot;: &quot;python3.14&quot;, &quot;type&quot;: &quot;symlink&quot; },\n          &quot;python3.14&quot;: { &quot;executable&quot;: true, &quot;size&quot;: 14264, &quot;type&quot;: &quot;regular&quot; }</code></pre>\n<p>That metadata turns out to be the perfect index for a FUSE filesystem that can lazily fetch the NARs from the cache and unpack them on-demand. 🤓</p>\n<p>None of this would mean anything without nixpkgs-multiverse, which already resolves any <code>(attribute, version)</code> in nixpkgs history to the store path Hydra built for it on cache.nixos.org.</p>\n<p>When you combine the two, you get a filesystem that can answer the question “where is <code>python3@3.6.2</code>” and then fetch it from the cache and unpack it for you, all without ever having to install it.</p>\n<p>I crawled all of it the <code>.ls</code> files in under twelve minutes. 🤯</p>\n<p>Once you have that, the filesystem writes itself:</p>\n<pre><code>$ ls /nix/store/2lb6nn8ivk1alhckv43n7734lqwbw7h9-python3-3.6.2/bin\n2to3      idle     pydoc     python   python3.6         python3-config  pyvenv\n2to3-3.6  idle3    pydoc3    python3  python3.6-config  python-config   pyvenv-3.6\n          idle3.6  pydoc3.6           python3.6m        python3.6m-config</code></pre>\n<p>That is CPython 3.6.2, from 2017. That <code>ls</code> <em>downloaded nothing</em>, it is answered from the pre-crawled index.</p>\n<h2 id=\"do-not-ls-the-tree\">§Do not <code>ls</code> the tree</h2>\n<p>Agents are “a thing”. Making them useful is a thing. Making them useful without installing anything is a thing.</p>\n<p>If your agent tried to <code>ls /omnibin/bin</code> and stat every single entry, it would have a really bad time. There are 881,933 binaries in the tree, and it would take a long time to stat them all.</p>\n<p>To help the agents out a bit, <code>ls /omnibin/bin</code> lists only the bare names, one per executable, each resolving to the newest package that provides it.</p>\n<p>The versioned forms all resolve, but they are not listed. For example, <code>python3</code> resolves to the latest Python 3, which is 3.14.6 at the time of writing, but <code>python3@3.6.2</code> resolves to the 2017 version.</p>\n<p>For everything else there is the index, which is sitting right there in the mount:</p>\n<pre><code>$ sqlite3 /omnibin/index.db \\\n    &quot;SELECT attr, version\n    FROM bins\n    WHERE name = &#39;python3&#39;\n    ORDER BY version&quot;</code></pre>\n<p>That UX is a little rough, so you can also use the <code>omnibin</code> CLI to query the index:</p>\n<pre><code>$ omnibin which python3\n/nix/store/gxzhl7aaiid7zp3y47jqqiq7zg5mqpwp-python3-3.14.6/bin/python3\n$ omnibin which --all python3 | wc -l\n610\n$ omnibin which --all ffmpeg | head -2\nffmpeg@3.1.7  ffmpeg  0.4 MB  /nix/store/0adpc3…-ffmpeg-3.1.7-bin/bin/ffmpeg\nffmpeg@3.2.4  ffmpeg  0.4 MB  /nix/store/nhfgdv…-ffmpeg-3.2.4-bin/bin/ffmpeg</code></pre>\n<p>Lastly, there is a /omnibin/README.md whose entire job is to tell whatever is exploring the filesystem to stop exploring the filesystem and query the database instead. 🤖</p>\n<h2 id=\"what-s-the-catch\">§What’s the catch?</h2>\n<p>At this point it should be obvious, but you pay for this on startup for the first access.</p>\n<pre><code>$ time python3@3.6.2 -c &#39;import sys; print(sys.version.split()[0])&#39;\n3.6.2\nreal    0m2.690s\n$ time python3@3.6.2 -c &#39;print(6*7)&#39;\n42\nreal    0m0.035s</code></pre>\n<p>The first run took 2.7 seconds to fetch the NARs and unpack them, the second run was instantaneous because the store paths were already present.</p>\n<p>Other than that? Not really, which is pretty amazing.</p>\n<p>For any long-lived machine, you would expect your <code>/nix/store</code> to already be warmed up with the packages you need, so the first access penalty is not a big deal.</p>\n<p>I remember one of the first things that blew my mind and sold me on Nix, was seeing a demo by @burke on comma. The capability to test a package, at a single nixpkgs revision, without “installing it”; revolutionary! I believe this to be a spiritual successor and I hope to imbue others with the same sense of wonder and amazement that I felt back then as a beacon of the power of Nix.</p>\n<p>The repo is at github.com/fzakaria/omnibin.</p>\n<p>Please <code>ls</code> responsibly.</p>","headings":[{"level":2,"text":"§What is this sorcery?","id":"what-is-this-sorcery"},{"level":2,"text":"§Do not ls the tree","id":"do-not-ls-the-tree"},{"level":2,"text":"§What’s the catch?","id":"what-s-the-catch"}]}}