nixpkgs-multiverse is a single Nix flake input that provides access to every version of every package that ever existed in Nixpkgs, across all 1,393 tracked revisions from 2017 to 2026. Instead of pinning multiple nixpkgs inputs (which are fetched eagerly and slow down evaluation), it uses lazy fetching via builtins.fetchTree with narHash, backed by two JSON files: revisions.json (1,393 revisions) and versions.json (289,521 distinct attribute/version pairs, 5.18 MB). The design stores only the newest revision per version to keep the index small. Performance is dramatic: 5 unused nixpkgs pins cost ~26 seconds at evaluation time, while nixpkgs-multiverse with 1,393 revisions available evaluates in a flat 0.20s. Revisions are memoized so fetching multiple packages from one revision costs the same as fetching one. The entire project is ~5 MB of JSON and ~200 lines of Nix.
Questions this post answers
Why does evaluating a Nix flake with multiple nixpkgs inputs take so long even when I only use one of them?
Nix flake inputs are fetched eagerly — all inputs are materialised at evaluation time regardless of whether the output references them. Each unused nixpkgs pin costs roughly 5 seconds, so five unused pins add about 26 seconds before any output evaluates. nixpkgs-multiverse avoids this by using builtins.fetchTree with narHash to fetch revisions lazily, only when actually referenced, keeping evaluation at a flat ~0.20s for 1,393 available revisions. Teams wrestling with slow Nix flake evaluation from pinned nixpkgs inputs track solutions like this on daily.dev.
How does nixpkgs-multiverse store version-to-revision mappings without the index file growing too large?
nixpkgs-multiverse stores only the most recent revision that shipped each package version, rather than every revision a version appeared in. This sparse encoding keeps versions.json at 5.18 MB covering 1,393 revisions and 289,521 distinct (attribute, version) pairs. An integer offset into revisions.json points to the correct revision, avoiding the linear size growth that comes from recording every occurrence. Nix developers building version-index tooling find design trade-offs like this discussed on daily.dev.
How do I run a specific historical version of a package like Python 3.6.2 using Nix flakes?
With nixpkgs-multiverse, you can run any historically available version directly: nix run 'github:fzakaria/nixpkgs-multiverse#versions.python3."3.6.2"' -- --version. You can also query all versions ever shipped for a package using the versionsOf function, or access a full Nixpkgs snapshot by release label, date, or commit hash via the at function. Nix users pinning historical package versions for reproducible environments share approaches like this on daily.dev.