Fast CLI for searching Nix packages from a local cache.
Live Web App (after deploy): https://tonky.github.io/nix-search/
Disclaimer: this was power-coded with LLM over a couple of hours.
Interactive TUI demo is shown above and recorded with VHS.
Regenerate it with:
vhs demo/nix-search.tapenix-search helps you quickly find the correct Nix attr path (for nix shell, nix profile install, flox install, etc.) without waiting on full Nix evaluation each time.
- Offline-first search from a local Tantivy index
- Fuzzy matching for typos and partial queries
- Exact attr lookup via
--attr - Interactive TUI when run in a terminal
- Script-friendly output modes:
--first,--plain,--json - Platform-aware ranking/filtering, with
--all-platformsoverride - Cache management commands:
cache update,cache status,cache clear - Browser/WebAssembly client with local artifact sync and cache diagnostics
This repository uses rustup with pinned settings from rust-toolchain.toml.
- Channel:
stable - Components:
rustfmt,clippy - Target:
wasm32-unknown-unknown
If you already have rustup installed, opening the repo is enough for Cargo commands to pick up the toolchain override.
For browser-side architecture, operations, and troubleshooting notes, see:
Additional implementation tracks:
The web client lives in crates/nix-search-web and reuses shared search logic from crates/nix-search-core.
Deployed static page: https://tonky.github.io/nix-search/
- Prepare local web data artifact and manifest:
just prep-web- Sync prepared data into static assets served by the web app:
just sync-web-data- Run Trunk dev server:
cd crates/nix-search-web
trunk serve --address 127.0.0.1 --port 4173Or use the single-command manual verify flow from repo root:
just verify-manualFor heavy data transforms (prep-web, cache update), release mode is materially faster.
- Prepare web data quickly (release profile):
just prep-web-fast- Update local index quickly (release profile):
just cache-update-fast- Capture a perf/size snapshot report under
tmp/bench/perf-size-<timestamp>/:
just perf-size-snapshot- Run size/runtime budget checks locally:
just perf-size-budget-check- Run full CI-equivalent checks locally (slower):
just perf-size-budget-check-fullFull mode now enforces a hard search-latency gate (search_p95_ms), while still reporting warning-level drift thresholds.
- Run quick checks in background (non-blocking) and inspect progress:
just perf-size-budget-check-bg
tail -f tmp/bench/perf-size-ci-bg/run.log
cat tmp/bench/perf-size-ci-bg/summary.txtInstall Playwright dependencies:
just e2e-installRun cross-browser smoke/diagnostics suite:
just e2e-testSpecs and config are in tests/e2e.
The GitHub Actions workflow wasm-data-publish.yml builds the prep artifact and deploys it to GitHub Pages.
You can run the same prep path locally:
cargo run -- prep-web --output tmp/pages-dataBuild/update cache:
nix-search cache updateInteractive search (TUI):
nix-search claude codePrint top match only (good for shell scripts):
nix-search --first "claude code"Search across all platforms (useful when current platform hides expected packages):
nix-search --all-platforms --first "cld cod"Exact attr lookup:
nix-search --attr claude-code --first xJSON output:
nix-search --json ripgrepUse with nix shell:
nix shell nixpkgs#$(nix-search --first "rust analyzer")- Package snapshot (primary source):
- URL:
https://raw.githubusercontent.com/pkgforge-dev/NixOS-Packages/main/nixpkgs.json - Used for searchable package records: attr path, pname, version, description, and platform inference from keys like
legacyPackages.<platform>.<attr>.
- URL:
- NixOS Search Elasticsearch (enrichment source, optional):
- Endpoint currently resolved from built-in candidates under
https://search.nixos.org/backend/.../_search. - Used only for detail metadata (homepage, license, maintainers, broken, longDescription).
- Endpoint currently resolved from built-in candidates under
- Package snapshot is called when:
nix-search cache updateis run.nix-search --update ...is used before search.- TUI starts and cache is older than
--ttl; refresh runs in background.
- Package snapshot request behavior:
- HTTP GET with conditional headers (
If-None-Match,If-Modified-Since) from stored metadata. - If server returns
304 Not Modified, no body is downloaded and cache timestamps/headers are refreshed. - If changed, JSON is parsed, grouped by attr path, and rebuilt into the local Tantivy index.
- HTTP GET with conditional headers (
- Elasticsearch is called only during TUI detail loading:
- On selection change, local enriched JSON cache is checked first.
- If missing and ES config is available, one POST request is sent with
size: 1and term query for the selected attr. - Response is cached to disk per attr path for instant reuse.
- Tantivy index and metadata are stored per channel under
~/.cache/nix-search/<channel>/. - Enriched details are cached as per-package JSON files under
~/.cache/nix-search/<channel>/enriched/. - Normal CLI searches (
--first,--plain,--json) read only local index data unless--updateis explicitly requested.
- Try exact attr lookup first (from
--attrornixpkgs#attrstyle input). - Otherwise run BM25 search on attr path, pname, and description.
- Apply fuzzy fallback and reranking heuristics.
- Apply platform split/filter (current platform by default, or
--all-platforms). - Render as interactive TUI or non-interactive output mode.
This design keeps search fast and mostly offline after cache build, while still allowing on-demand rich metadata in the TUI.
