nh: a unified CLI for NixOS, Home Manager and nix-darwin
Yet another Nix CLI helper. [Maintainers=@NotAShelf, @faukah]
At a glance
- What is it?
- nh reimplements the commands NixOS users type every day (os switch, home switch, darwin switch, clean, search) behind one Rust binary. The README is unusually confident about documentation; the actual behaviour is thinner in places.
- Who is it for?
- nh suits people who already run NixOS, Home Manager or nix-darwin and want one binary instead of three command families, plus diff review before activation. It is the wrong tool if you only need plain Nix expressions, or if you depend on flags their underlying tools support and nh has not reimplemented.
- Can I use it commercially?
- Yes, with conditions. EUPL-1.2 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem nh solves: three command families, three sets of flags
A NixOS user with Home Manager and a flake ends up juggling several tools with overlapping but inconsistent interfaces. `nixos-rebuild` handles the system, `home-manager` handles the user profile, `darwin-rebuild` handles macOS, `nix-collect-garbage` handles cleanup, and searching Nixpkgs means either `nix search` or a web search. Each has its own flag conventions and its own output format.
nh's stated goal is to consolidate these into one CLI with subcommands: `os`, `home`, `darwin`, `search`, `clean`. The README calls it a reimplementation rather than a wrapper, and is explicit that it is not a nixos-rebuild wrapper and is not constrained by such a tool's limits. That distinction matters for what you can expect: nh builds its own argument parsing and its own execution path rather than shelling out to the original command with translated flags. The audience is people already inside the Nix ecosystem who are tired of remembering which tool takes `--flake` and which takes `-f`.
How nh is structured: a Rust workspace with one crate per workflow
The repository is a Cargo workspace, and the crate names map closely to the subcommands. `crates/nh-nixos`, `crates/nh-home`, `crates/nh-darwin`, `crates/nh-clean`, and `crates/nh-search` sit alongside `nh-core`, `nh-config`, `nh-diff`, `nh-installable` and `nh-remote`. There is also a `crates/nix-command` and a `crates/nix-installable` at version 0.2.3 and 0.1.0, separate from the 4.4.2 workspace version, which suggests they are intended as reusable pieces rather than internal-only modules.
The workspace pins edition 2024 and `rust-version = "1.95.0"`, so building from source requires a recent toolchain. The dependency list is where the visible behaviour comes from: `clap` with the `derive`, `env` and `unstable-styles` features for the CLI surface, `clap_complete` and `clap_complete_nushell` for shell completions, `clap_mangen` for man pages, `indicatif` for progress output, `inquire` for prompts, `dix` for diffing, and `elasticsearch-dsl` for the search path. That last one explains the README's claim that `nh search` queries Nixpkgs via Elasticsearch rather than resolving locally.
The diffing crate is the interesting design choice. `nh os switch` and its siblings can show derivation changes before activation, which means nh is not just a dispatcher; it parses and compares build output. The README describes this as "Integrated, super-fast diffing of derivation changes before activation or switch." Whether that diff is complete for every flake shape is not something the README addresses.
Installing nh and running a first switch
The README recommends the nixpkgs package, which it calls NH stable, because tagged releases get more testing. The development version comes from the flake output. Both forms are one command, and neither requires a permanent install:
nix shell nixpkgs#nh # stable
nix shell github:nix-community/nh # devAfter that, the first real use is a system switch. For a flake-based configuration the README gives a single positional path:
nh os switch /path/to/flakeFor a classical configuration using channels, the flake flag is replaced with `-f` and the installable expression, and any extra arguments go after `--`:
nh os switch -f '<nixpkgs/nixos>'
nh os switch -f '<nixpkgs/nixos>' -- -I nixos-config=/path/to/configuration.nixYou should see the build tree as the derivation builds, then a diff of what changed, then the activation step. The README points to `nh os --help` and `man 1 nh` for the remaining values and for defaults that come from environment variables.
If you want cleanup handled automatically, the NixOS module wires `nh clean` in as a service:
{
programs.nh = {
enable = true;
clean.enable = true;
clean.extraArgs = "--keep-since 4d --keep 3";
flake = "/home/user/my-nixos-config"; # sets NH_OS_FLAKE variable for you
};
}The `flake` option is the one to notice: setting it exports `NH_OS_FLAKE`, so later `nh os` invocations do not need the path passed again.
Specialisations and generation management are the parts that go beyond a wrapper
Two features in the README are not available in the tools nh replaces at the same level. The first is specialisation handling. NixOS specialisations produce multiple activation scripts, and nh detects which one is running by reading a name from `/etc/specialisation`. The README's example writes that file from the specialisation's own configuration. Without that file, nh has no way to know which activation script applies, so this is a convention you have to adopt rather than something nh infers.
The second is generation management. The README says nh can inspect, roll back and manage system generations with explicit targeting, and that `nh clean` extends `nix-collect-garbage` with gcroot cleanup, profile targeting and time-based retention. The retention flags in the module example, `--keep-since 4d --keep 3`, are the concrete form of that. gcroot cleanup is the part worth calling out: stale gcroots are a common reason a `nix-collect-garbage` run frees less space than expected, and the underlying tool does not handle them for you.
Where nh gets in the way
The README states that everything nh does is documented and that the user-facing documentation will always remain up to date. That is a strong claim, and the sections visible here do not cover every subcommand in the same depth. There is no documented rollback procedure for a failed switch, no description of what happens if the diff step fails, and no guidance on behaviour when Elasticsearch is unreachable during `nh search`. Treat the documentation claim as an aspiration and check `--help` output for the subcommand you actually need.
The classical configuration support is the other soft spot. The README itself calls the post-4.0 API "mature, but somewhat experimental as it is a new addition" and asks for bug reports. Flake users are on the better-tested path. If your configuration pins dependencies manually or uses channels with a non-default `nixos-config` path, you are relying on the newer code path.
Finally, nh is a reimplementation, not a passthrough. Any flag your original tool supports that nh has not implemented is simply unavailable, and the README does not publish a compatibility matrix. If you script `nixos-rebuild` with uncommon flags today, check `nh os --help` before assuming parity. The README notes that future goals include `nixos-install` and `nixos-generate-config` support, which confirms those are not covered now.
nh against nvd, and against just using the original tools
The closest alternative for the diff feature is nvd, which compares two NixOS generations and prints the version changes between them. The difference is placement in the workflow. nvd is a standalone comparison tool you run after a build or between two store paths; nh folds the diff into the switch itself, so you see the changes before activation rather than after. If your only interest is inspecting what changed between two existing generations, nvd does that job on its own and does not require adopting a new switch command.
The other alternative is not adopting anything: keep `nixos-rebuild switch`, `home-manager switch`, `darwin-rebuild switch` and `nix-collect-garbage` as they are. That path has no new failure modes, no new dependency on a Rust binary in your PATH, and no experimental code path for classical configurations. What you give up is the unified interface, the build-tree output, the pre-activation diff, and the gcroot handling in `nh clean`. For a single-machine flake setup where you already know the flags, the trade may not be worth it. For someone running NixOS plus Home Manager plus a second macOS machine, the consolidation is the point.
Maintenance, packaging and the EUPL-1.2 licence
The last push to the repository was on 2026-09-22, two days before the date used here, and the project is not archived. The most recent tagged release is v4.4.2 from 2026-07-28, following v4.4.1 on 2026-07-07 and v4.4.0 on 2026-07-04. Releases cluster, so the gap between tags is not a reliable signal of activity; the commit history is the better indicator, and it is current.
Upgrade cost is low if you install from nixpkgs. nh is packaged in both nixpkgs stable and unstable, and the README says updates are backported to stable outside extreme circumstances, so a `nix flake update` on your nixpkgs input moves you forward. The README also asks users to file an update request against Nixpkgs if the packaged version is stale, which implies the nixpkgs version can lag the repository. If you need a specific recent release, the flake output tracks development instead.
The licence is EUPL-1.2, a copyleft licence written for the European Union and available in multiple languages. It is not the MIT or Apache-2.0 licence most Rust tooling uses, so if you plan to vendor nh's crates into a larger product, read the licence text rather than assuming permissive terms. This is a description of the licence identifier, not legal advice; the LICENSE file in the repository is the authoritative text.
Editorial conclusion
nh suits people who already run NixOS, Home Manager or nix-darwin and want one binary instead of three command families, plus diff review before activation. It is the wrong tool if you only need plain Nix expressions, or if you depend on flags their underlying tools support and nh has not reimplemented. Verify first that your nixpkgs channel carries the version you want, and read `nh os --help` before switching, because the flake and channel forms take different arguments.
Frequently asked questions
How do I install nh?
The README recommends the nixpkgs package, called NH stable, and gives `nix shell nixpkgs#nh` to try it without installing. The development version comes from the flake output via `nix shell github:nix-community/nh`.
Does nh work with classical NixOS configurations, or only flakes?
Both. The README states that as of 4.0 nh supports flakes and classical configurations via channels or manual dependency pinning, though it describes the new API as mature but somewhat experimental. For flakes the command is `nh os switch /path/to/flake`; for classical setups it is `nh os switch -f '<nixpkgs/nixos>'`.
What does nh clean do that nix-collect-garbage does not?
The README says `nh clean` extends `nix-collect-garbage` with gcroot cleanup, profile targeting and time-based retention. The NixOS module example uses retention flags in the form `--keep-since 4d --keep 3`.
Can nh manage NixOS specialisations?
Yes, but it needs to be told which one is running. The README says nh detects the active specialisation by reading its name from `/etc/specialisation`, and the configuration must write that file.
Is nh a nixos-rebuild wrapper?
No. The README states explicitly that nh is not a nixos-rebuild wrapper and is not constrained by the limits of such tools, describing it instead as a reimplementation with additional commands and flags.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nix-community-nh)