Interactive visualizer for Nix flakes — built for dendritic (flake-parts + import-tree) configurations, works on any flake.
Three panes:
- Left — outputs & modules. Every flake output (
nixosConfigurations,darwinConfigurations,packages,overlays, …). Expanding a configuration reveals its module hierarchy: your own module files in their directory (mounting) structure, plus per-input subtrees for modules that come from flake inputs. Badges count customized options per subtree. - Center — detail. Selecting a module shows Configures (option values
this file sets — with
mkForce/mkDefaultpriority chips and customized-vs-defaulted styling) and Declares (options this file defines — type, default, current value). Hovering an option shows its type, default, priority, and description. Modules from inputs show full provenance fromflake.lock(url, rev, narHash, lastModified). - Right — files. Every
.nixfile the flake references, grouped by origin (self first, then inputs). Hovering a file highlights the modules it customizes on the left; selecting it shows its last git commit and which files import it / it imports.
Selections are deep-linkable (URL hash); light/dark theme; colors are stable per file/input (curated CVD-safe slots + OKLCH hash colors).
Deeper docs live in docs/ — architecture, the extractor
pipeline, the data contract, the SPA, testing — rendered at
kris.net/flake-explorer/docs with a
generated API reference alongside
the live demo (the explorer browsing its
own flake). Release notes: CHANGELOG.md.
$ nix run github:kriswill/flake-explorer -- serve /etc/nixos
flake-explorer serving /etc/nixos at http://localhost:4321Or from npm (@kriswill/flake-explorer) —
nix must be on PATH either way:
$ bunx @kriswill/flake-explorer serve /etc/nixos
$ npx @kriswill/flake-explorer serve /etc/nixos # installs bun on demandserve extracts the cheap manifest up front and evaluates each
configuration's options on demand the first time you open it (cached by
flake narHash; a full NixOS system takes a minute or two the first time).
After editing the flake, POST /api/refresh re-scans it (manifest + cache
reconcile) without restarting the server:
$ curl -X POST localhost:4321/api/refreshPre-extract instead with:
$ flake-explorer extract /etc/nixos --all # every configuration
$ flake-explorer extract . --configs nixos/myhost # just oneFlags: --out DIR (data dir, default ./flake-explorer-data), --port N,
--all-systems, --timeout SECS.
export materializes the explorer into one standalone HTML file — no
server, no nix, no runtime dependencies. Open it from file://, or host it
anywhere static files go (a CDN, GitHub Pages):
$ flake-explorer export /etc/nixos --all # every configuration
$ flake-explorer export . --configs nixos/myhost --html myhost.htmlThe manifest (outputs, inputs, files, import graph) is always included;
--configs kind/name,... / --all pick which configurations' options are
embedded (the rest show a "not included in this export" notice). The flake's
own sources and each input's flake.nix are embedded by default;
--sources all also embeds every file the exported configurations reference
— beware that against nixpkgs-based systems this means thousands of module
sources and a file that can reach tens of MB (GitHub Pages caps a single
file at 100 MB).
This repo publishes its own export on every push to main via
.github/workflows/pages.yml —
flake.html. To do the
same, copy that workflow and set the repo's Pages source to "GitHub Actions"
(Settings → Pages).
- One
extract.nixevaluated vianix eval --impure --json(uses YOUR nix, never a vendored one, so store paths and registry match your system). - Options are walked chunk-by-chunk (per top-level namespace, splitting
failing chunks recursively) because
builtins.tryEvalcannot catch missing-attribute/type errors — one poisoned option costs itself, not the whole configuration. Values degrade gracefully (full → no values → no values+descriptions) and every degradation is surfaced as a warning. - Customized-vs-default is decided by definition priority
(
highestPrio < 1500), notisDefined— every option with a default is "defined" by its own declaration. - Files are attributed to inputs by store-path prefix (including transitive
inputs and patched trees à la
nixpkgs.applyPatches); your own files get per-filegit loginfo.
$ nix develop # bun + git
$ bun install
$ bun flake-explorer.ts serve /etc/nixos
$ bun test # unit tests (happy-dom)
$ bunx svelte-check --tsconfig ./tsconfig.json
$ nix build # package + offline test derivation
$ bun run docs # build the docs site into _site/docsSvelte 5 (runes) bundled by Bun.build + bun-plugin-svelte — no Vite.
Data contract between the extractor and the SPA lives in src/schema.ts.
MIT
