## What Does it Do?
NH is a modern helper utility that aims to consolidate and reimplement some of
the commands and interfaces from various tools within the Nix/NixOS ecosystem.
Our goal is to provide a **cohesive**, **easily-understandable** interface with
more features, better ergonomics and at many times better _speed_. In addition
to acting as a super-convenient, all-in-one utility that reimplements well-known
and commonly used Nix commands, NH is a _pretty_ tool that brings together
relevant 3rd party projects that you might be familiar with.
To get started with NH, skip to the [Usage](#usage) section.
## Features
- **Unified CLI**: Consistent, intuitive interface for many **Nix**, **NixOS**,
**Home Manager**, and **Darwin** workflows.
- **Rich Interface**: Each major function (`os`, `home`, `darwin`, `search`,
`clean`) exposes granular subcommands and flags for fine-tuned control.
- **Enhanced Garbage Collection**: `nh clean` extends `nix-collect-garbage`
with gcroot cleanup, profile targeting, and time-based retention.
- **Faster Nix Search**: search Nixpkgs via Elasticsearch for faster results
- **Eye Candy**: It looks great, without any compromise. I mean who does not
love some cool looking UIs?
- **Build-tree Visualization**: `nh os` and similar commands display build
trees for clear dependency tracking.
- **Diff & Change Review**: Integrated, super-fast diffing of derivation
changes before activation or switch.
- **Specialisation Support**: Easily select or ignore NixOS & Home-Manager
specialisations via flags.
- **Generation Management**: Inspect, rollback, and manage system generations
with explicit targeting.
- **Extensible & Futureproof**: Designed for seamless, rapid addition of new
subcommands and flags.
- **NH is a reimplementation of the CLIs you all know and love**, but with a
focus on safety and correctness. The language and design choices allow new
feature additions to be trivial and (almost) zero-cost.
- **Excellent Documentation**: Everything you can do with NH is documented.
Everything NH _does_ is documented. The user-facing and developer-facing
documentation is, and will always remain, up to date.
### Design
[Discussions]: https://github.com/nix-community/nh/discussions
[Issues]: https://github.com/nix-community/nh/issues
NH is an _unified_ CLI, meaning it aims to bring together core platform support
into a single, convenient utility. For the time being, this appears in NH's
interface as support for **NixOS** (first-class), **Home Manager** and
**Nix-Darwin**. We hope to provide a familiar, convenient and _good looking_
interface for users of any and all of those projects.
The familiar interface of NH should not be seen as a weakness, however, as NH is
NOT a nixos-rebuild wrapper, and is not constrained by the limits of such tools.
Simply put, our goal is to implement _not only_ what is available but instead go
above and beyond to implement additional commands and flags to **improve the
experience provided by the default tools**. Which is to say _plumbing_ and _sane
defaults_ matter. You get to enjoy the very tools that you are accustomed to,
with the benefits of a faster and safer language.
> [!IMPORTANT]
> Future goals of NH include providing support for lower-levels tools, such as
> `nixos-install`, and `nixos-generate-config` to become a drop-in replacement
> for most critical tools with the benefits of Rust. If you would like to
> provide feedback and create feature requests, those are welcome over at the
> [Discussions] and [Issues] tabs respectively.
## Status
[update request]: https://github.com/NixOS/nixpkgs/issues
NH is packaged in nixpkgs, and is available under both nixpkgs stable and
nixpkgs unstable. Outside of extreme circumstances, all updates will be
backported to the stable branch. Refer to the [installation](#installation)
section for more details. Make sure you submit an [update request] in Nixpkgs if
the package is outdated.
### Installation
The latest, tagged version is available in Nixpkgs as **NH stable**. This is
recommended for most users, as tagged releases will usually undergo more
testing. This repository also provides the latest development version of NH,
which you can get from the flake outputs.
```sh
nix shell nixpkgs#nh # stable
nix shell github:nix-community/nh # dev
```
You can try NH in a Nix shell today, no setup required!
### NixOS
We provide a NixOS module that integrates `nh clean` as a service. To enable it,
set the following configuration:
```nix
{
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
};
}
```
> [!TIP]
> As of 4.0, NH fully supports both **Nix flakes** and classical NixOS
> configurations via channels or manual dependency pinning and the such. Please
> consider the new API mature, but somewhat experimental as it is a new
> addition. Remember to report any bugs!
>
> - For flakes, the command is `nh os switch /path/to/flake`
> - For a classical configuration:
> - `nh os switch -f ''`, or
> - `nh os switch -f '' -- -I nixos-config=/path/to/configuration.nix`
> if using a different location than the default.
You might want to check `nh os --help` or `man 1 nh` for other values and the
defaults from environment variables.
#### Specialisations support
NH is capable of detecting which specialisation you are running, so it runs the
proper activation script. To do so, you need to give NH some information of the
spec that is currently running by writing its name to `/etc/specialisation`. The
config would look like this:
```nix
{config, pkgs, ...}: {
specialisation."foo".configuration = {
environment.etc."specialisation".text = "foo";
# ..rest of config
};
specialisation."bar".configuration = {
environment.etc."specialisation".text = "bar";
# ..rest of config
};
}
```
#### Home-Manager
Home specialisations are read from `~/.local/share/home-manager/specialisation`.
The config would look like this:
```nix
{config, pkgs, ...}: {
specialisation."foo".configuration = {
xdg.dataFile."home-manager/specialisation".text = "foo";
# ..rest of config
};
specialisation."bar".configuration = {
xdg.dataFile."home-manager/specialisation".text = "bar";
# ..rest of config
};
}
```
## Usage
One of the features and the core principles of NH is to provide a clean, uniform
and intuitive CLI for its users. The `nh` command offers several subcommands,
all with their extensive CLI flags for extensive configuration.
> [!TIP]
> NH supports various flags, [environment variables](#environment-variables) and
> setup options to provide the best possible user experience. See the `--help`
> page for individual subcommands, or `man 1 nh` for more information on each
> subcommand with examples. You may also use the relevant platform module, such
> as the NixOS module available in Nixpkgs, to customize it for your system as
> described in the installation section.
Under the `nh` command, there are two types of commands that you'll be
interested in:
### Global Subcommands
Global subcommands implement functionality around core Nix commands. As it
stands, we provide a **better search** and **better garbage collection**
experience, done so with two subcommands provided out of the box.
#### `nh search`
[SPAM]: https://github.com/feel-co/SPAM
We provide a super-fast search tool for Nix packages and NixOS/Home Manager
options (powered by an Elasticsearch client against search.nixos.org), offline
search against local [SPAM] databases, and Nixpkgs pull request and issue
search. All available as `nh search`!
The command exposes several explicit subcommands and a convenient shorthand:
[found here]: https://github.com/feel-co/spam/actions/workflows/auto-index.yml
| Invocation | What it does |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `nh search ` | Shorthand; searches packages by default (see `NH_DEFAULT_SEARCH`.) |
| `nh search packages ` | Search Nixpkgs packages via elasticsearch API. |
| `nh search options [--scope=] ` | Search NixOS/Home Manager/nix-darwin options (`--scope`: `nixpkgs`, `home-manager`, `nix-darwin`, `all`.) |
| `nh search offline --db ` | Search a local [SPAM] database without network access. Generated DBs can be [found here]. |
| `nh search prs [--days ] ` | Search Nixpkgs pull requests and show branch reachability for merged PRs. Defaults to updates in the last 15 days. |
| `nh search issues [--days ] ` | Search Nixpkgs issues, excluding pull requests. Defaults to updates in the last 15 days. |
> [!TIP]
> Offline search queries every `pkg`, `opt`, and `lib` scope present by default.
> Pass `--scope pkg`, `--scope opt`, or `--scope lib` to search only that scope
> across all `--db` files. Files without the selected scope yield no results.
`--json` is shared by all search modes. `--limit`, `--channel`, and
`--platforms` are available on the modes that use them and on the shorthand
form. `nh search prs` and `nh search issues` use `GH_TOKEN` for GitHub
authentication. If `GH_TOKEN` is unset, NH reads the token from
`NH_GITHUB_TOKEN_FILE`, or from `$XDG_STATE_HOME/nh/github-token` falling back
to `~/.local/state/nh/github-token`. If no token is found in an interactive
terminal, NH prompts for one and saves it to that token file.
#### `nh clean`
Reimplementation of `nix-collect-garbage` that also collects gcroots with
various options for fine-graining what is kept, and additional context before
the cleanup process to let you know what is to be cleaned.
> [!NOTE]
> By default `nh clean` will automatically clean up your
> [gcroots](https://nixos.org/guides/nix-pills/11-garbage-collector.html#indirect-roots)
> directory, which will remove all your built result and direnv directories.
>
> Use `--no-gcroots` to skip all gcroot cleanup, or `--no-direnv` to preserve
> direnv gcroots while still cleaning everything else.
### Platform Specific Subcommands
Platform specific subcommands are those that implement CLI utilities for
**NixOS**, **Home Manager** and **Nix-Darwin**.
#### `nh os`
The `nh os` subcommand reimplements the Python script, `nixos-rebuild-ng`, [^1]
from ground up _with the addition of_:
- Build-tree displays via **rom**.
- Pretty diffs of changes via **dix**
- Confirmation
- `nh os dry-activate` builds a configuration and previews activation without
applying it; `nh os switch --dry` builds without running activation.
- `nh os build --dry` shows what a local build would do without building it.
- `nh os info --json` reports running and boot-default generations separately.
and other additional changes to make the UI more intuitive, from supporting
environment variables to additional safeguards. Is this all? No, more is to
come.
#### `nh home`
The `nh home` subcommand reimplements the `home-manager` script, with the same
additions as `nh os`.
#### `nh darwin`
Last but not least, the `nh darwin` subcommand is a pure-rust reimplementation
of the `darwin-rebuild` script featuring the same additions as `nh os` and
`nh home`.
[^1]: `nh os` does not yet provide full feature parity with `nixos-rebuild`.
While a large collection of subcommands have been implemented, you might be
missing some features. Please visit
[#358](https://github.com/nix-community/nh/issues/358) for a roadmap.
### Command Examples
| Platform | Old Command (Without NH) | New Command (With NH) |
| ------------ | ---------------------------------------- | ------------------------------ |
| NixOS | `nixos-rebuild switch --flake .#myHost` | `nh os switch . -H myHost` |
| Darwin | `darwin-rebuild switch --flake .#myHost` | `nh darwin switch . -H myHost` |
| Home Manager | `home-manager switch --flake .#myHost` | `nh home switch . -c myHome` |
If the `NH_FLAKE` variable is set, NH allows omitting the path to your flake.
This is done automatically in the modules for NH in the NixOS and Home-Manager
modules if `programs.nh.flake` is set.
NH also allows omitting the hostname (`-H`) for NixOS/Darwin and the
configuration (`-c`) parameters when it can be autodiscovered on the system. For
example, if `NH_FLAKE` or `NH_OS_FLAKE` is set you may simply run `nh os switch`
with no additional arguments, and it will automatically resolve
`nixosConfigurations.`.
Additionally, NH also allows omitting the path to your non-flake nix config. You
can specify the Nix file and Nix attribute path with the `NH_FILE` and
`NH_ATTRP` environment variables. If `NH_FILE` and `NH_ATTRP` are both set,
`nh os switch` effectively evaluates `$NH_FILE#$NH_ATTRP`.
## Environment variables
NH supports several environment variables to control command behaviour. Some of
the common variables that you may encounter or choose to employ are as follows:
### Global
- `NIX_SSHOPTS`, `NIX_CONFIG`, `NIX_REMOTE`, `NIX_SSL_CERT_FILE` and
`NIX_USER_CONF_FILES` are forwarded in all Nix commands with environment
isolation. `NH_SSHOPTS` takes precedence over `NIX_SSHOPTS` when both are set.
- `NIX_SUDOOPTS` - Extra sudo arguments forwarded to the `sudo` invocation;
supported for nixos-rebuild compatibility. `NH_SUDOOPTS` takes precedence when
both are set.
- `NIXOS_INSTALL_BOOTLOADER`
- This is a variable accepted by `switch-to-configuration`, which handles the
system switching behind the scenes. If `true`, `switch-to-configuration`
will call the necessary script to force installation of your bootloader.
This behaviour can also be replicated by passing `--install-bootloader` to
`nh os switch` and `nh os boot` commands.
- `NIXOS_NO_CHECK` - Forwarded to `switch-to-configuration` during activation.
Inhibits certain NixOS service checks.
### NH Specific
- `NH_ASK`
- When set to a truthy value such as `1`, `true`, `yes`, or `on`, asks for
confirmation before applying supported operations. Falsy values such as `0`,
`false`, `no`, or `off` disable it. Equivalent to `--ask`.
- `NH_ROM`
- Forces whether rom shows build progress. Without it, rom runs only when
stdout is a terminal, and stays off when stdout is a pipe or file, such as
in CI or under an agent. Set to `1`, `true`, `yes`, or `on` to force rom on,
or `0`, `false`, `no`, or `off` to force it off. `--no-rom` still takes
precedence. `NH_NOM` is a deprecated alias that will be removed in 5.0.
- `NH_ROM_LOG`
- Path to a file that records the Nix log stream of builds shown by rom, so it
can be replayed through rom.
- `NH_NO_CHECKS`
- When set (any non-empty value), skips startup checks such as Nix version and
experimental feature validation. Useful for generating completions or
running in constrained build environments. You can also consider this an
"expert flag" that you can set for a non-zero performance benefit. It
assumes you know what you are doing.
- `NH_FLAKE`
- Preferred path/reference to a directory containing your `flake.nix` used by
NH when running flake-based commands. Historically `FLAKE` was used; NH will
migrate `FLAKE` into `NH_FLAKE` if present and the specific `NH_*_FLAKE`
vars are not set.
- `NH_OS_FLAKE`, `NH_HOME_FLAKE`, `NH_DARWIN_FLAKE`
- Command-specific flake references for `os`, `home`, and `darwin` commands
respectively. If present they take precedence over `NH_FLAKE`.
- `NH_SUDO_ASKPASS`
- Path to a program used as `SUDO_ASKPASS` when NH self-elevates with `sudo`.
If set and `sudo` is used for elevation, NH will pass `-A` to `sudo` and set
`SUDO_ASKPASS` accordingly.
- `NH_SUDOOPTS`
- Extra arguments inserted into the `sudo` invocation when NH elevates
privileges. Accepts the same shell-quoted format as `NIX_SUDOOPTS`, which it
takes precedence over.
- `NH_SSHOPTS`
- SSH options for remote operations. Accepts the same format as `NIX_SSHOPTS`,
which it takes precedence over.
- `NH_ELEVATION_STRATEGY`
- Privilege elevation strategy. Accepted values include `auto`, `none`,
`passwordless`, `empty-password`, and `program:`. Use `empty-password`
for remote sudo setups where PAM authenticates out-of-band, such as
`pam_rssh` with a security key, and expects an empty stdin password line.
- `NH_PRESERVE_ENV`
- Controls whether environment variables marked for preservation are passed to
elevated commands. Set to `"0"` to disable preservation, `"1"` to force
preservation. If unset, preservation defaults to enabled.
- `NH_CONTINUE_ON_ACTIVATION_FAILURE`
- For `nh os switch`, activation runs before the new generation is added to
the bootloader. By default a failed activation aborts the switch, so the
generation is not added to the bootloader. Setting this to `"1"` (or passing
`--continue-on-activation-failure`) continues to the bootloader step
regardless, so the generation is still bootable on next reboot.
- `NH_LOG`
- Sets the tracing/log filter for NH. This uses the same format as
`tracing_subscriber` env filters (for example: `nh=trace`).
- `NH_CONFIG`
- Overrides the path to the NH configuration file. If unset, NH uses
`$XDG_CONFIG_HOME/nh/config.toml`, falling back to
`~/.config/nh/config.toml`.
- `GH_TOKEN`
- GitHub token used by `nh search prs` and `nh search issues`. If set, this
takes priority over any token file.
- `NH_GITHUB_TOKEN_FILE`
- Overrides the path to the GitHub token file used by `nh search prs` and
`nh search issues` when `GH_TOKEN` is unset. If unset, NH uses
`$XDG_STATE_HOME/nh/github-token`, falling back to
`~/.local/state/nh/github-token`. Tokens entered through the interactive
prompt are saved to this file with user-only permissions.
- `NH_SEARCH_CHANNEL`
- Default Nixpkgs channel used by `nh search packages` and `nh search options`
(e.g. `nixos-unstable`, `nixos-24.11`). Overridden per-invocation by
`--channel`.
- `NH_SEARCH_JSON`
- When set to a truthy value, `nh search` outputs results as raw JSON instead
of the formatted display. Equivalent to `--json`.
- `NH_SEARCH_PLATFORM`
- When set to a truthy value, supported platforms are shown for each package
result. Equivalent to `--platforms`.
- `NH_DEFAULT_SEARCH`
- Controls the target of the `nh search ` shorthand when no subcommand
is given. Accepted values: `packages` (default), `options` (uses scope
`all`). Equivalent to `--default-search`.
- `NH_SEARCH_BACKEND_VERSION`
- Backend index version queried on search.nixos.org by `nh search packages`
and `nh search options`. By default nh queries the newest index available
for the channel, falling back to the version bundled with nh if that cannot
be determined. Use this to pin a specific index. Equivalent to
`--backend-version`.
- `NH_SEARCH_BACKEND_FALLBACKS`
- Number of newer index versions to try when the requested version is outdated
(missing on the backend). Defaults to `1`, so nh retries the next version
once before failing. Equivalent to `--backend-version-fallbacks`.
- `NH_OFFLINE_DB`
- Colon-separated list of paths to SPAM database files used by
`nh search offline`. Each path is treated as a separate database. Equivalent
to passing `--db` multiple times. Example:
`NH_OFFLINE_DB=/var/cache/spam/nixpkgs.db:/var/cache/spam/hm.db`.
### Notes
- Any environment variables prefixed with `NH_` are explicitly propagated by NH
to commands when appropriate, i.e., in environment isolation.
- For backwards compatibility, if `FLAKE` is present and none of the
command-specific `NH_*_FLAKE` variables exist, NH will set `NH_FLAKE` from
`FLAKE` and emit a warning recommending migration to `NH_FLAKE`. `FLAKE` will
be removed in the future versions of NH.
## Frequently Asked Questions (FAQ)
**Q**: Does NH wrap the CLIs that I typically use?
**A**: No, all of the commands use Nix directly, and they **do not consume the
typical CLI utilities**. NH is slowly converting existing tools that are invoked
via shell to native Rust libraries to get safer integration and slightly better
performance.
## Hacking
Contributions are always welcome. To get started, just clone the repository and
run `nix develop`. We also provide a `.envrc` for Direnv users, who may use
`direnv allow` to enter a shell with the necessary dependencies.
### Structure
[cargo-xtask]: https://github.com/matklad/cargo-xtask
NH is written in the Rust programming language, and consists of two modules. The
core of NH is found in the `src` directory, and is separated into different
modules. Some of the critical modules that you may want to be aware of are
`nh::commands` for command interfaces, `nh::checks` for pre-startup checks and
`nh::util` to store shared logic. Platform-specific logic is placed in the
appropriate platform module, such as `nh::nixos` or `nh::darwin` with generic
helpers placed in `nh::util`.
The `xtask` directory contains the [cargo-xtask] tasks used by NH, used to
generate manpages and possibly more in the future.
### Submitting Changes
Once your changes are complete, please remember to run `just fix` to apply
general formatter and linter rules that will be expected by the CI.
You will also want to update the [changelog](/CHANGELOG.md) with sufficient
amount of information to detail the new behaviour before you create your
changes.
This might seem daunting, but it isn't. Even if you _don't_ meet those
requirements, you'll be gently nudged to make your changes. Friendly
contributions are always welcome.
## Attributions
[faukah]: https://github.com/faukah
[ViperML]: https://github.com/viperML
[nvd]: https://sr.ht/~khumba/nvd/
[dix]: https://github.com/faukah/dix
[rom]: https://github.com/manic-systems/rom
[crates]: /Cargo.toml
NH has had a long history, and it has grown a lot over the years. I, NotAShelf,
would first like to extend my thanks to [ViperML] for his immense efforts as the
creator and the first maintainer of NH. I have recently taken over NH, but none
of this would be possible without him.
Next, I would like to thank the tools we run under the hood. The visualization
of upgrade diffs are provided by the [dix] crate, which is created by my good
friend [faukah]. Compared to the previous diffing utility, [nvd], dix is more
than twice as fast and has been a blessing to NH's diffing experience. Thank
you!
[rom] provides NH's build tree and streaming build-log presentation.
I also would like to extend my thanks to the many Rust [crates] that power NH
under the hood and give it its signature UX. Without the beautiful Rust
ecosystem, NH could not be where it is.
Last but not least I would like to thank... YOU! Thank you to everyone who has
contributed to NH, talked about NH or criticized NH to allow further
improvement. NH would not be where it is without you.