Source and license: the translations and adaptations of the upstream README in this article’s “What is nh?”, “Features”, “Current status”, “Usage”, “Environment variables”, “Frequently asked questions”, and “Contributing” sections come from the nix-community/nh project and its contributors. Those upstream materials and their translations, arrangement, and revisions are provided under EUPL-1.2 (full license); that license is not extended to the independent module configuration reference, this site’s added workflow-order guidance, or other content. License verification is based on the upstream README at pinned reference revision 25da175ed916 and its LICENSE. This revision is the reference used for this verification, not a claim about the exact revision originally imported. This article includes translation, selection, and supplementary explanations; this license and modification notice was added on 2026-10-09. The editable source of this article retains the translated and adapted content. “We” in the original text refers to the upstream project and does not imply upstream endorsement of this site.
What is nh?#
Source scope: this article preserves the translation of upstream nh documentation and module-option explanations from the original notes. The source includes development-branch features, such as SPAM offline search and GitHub PR/issue search, which are not guaranteed to be present in every distribution’s stable package. Check the installed version with nh --version, each subcommand’s --help, and the corresponding source.
nh is a modern helper designed to unify and reimplement the commands and interfaces of several tools in the Nix/NixOS ecosystem. Our goal is to provide a consistent, easy-to-understand interface with more features, a better user experience, and greater speed. Beyond being an all-in-one tool that reimplements familiar, frequently used Nix commands, nh is also _pleasant to look at_, integrating related third-party projects you may already know.
For a quick start, begin with “Usage” and “Command examples.”
Features#
- A unified CLI: a consistent, intuitive interface for Nix, NixOS, Home Manager, and Nix-Darwin workflows.
- A rich interface: each major feature (
os,home,darwin,search,clean) provides fine-grained subcommands and arguments for precise control. - Enhanced garbage collection:
nh cleanextendsnix-collect-garbagewith gcroots cleanup, profile selection, and time-based retention. - Faster Nix search: search Nixpkgs through Elasticsearch for faster responses.
- Good looks: attractive without compromise. Who does not enjoy a great-looking interface?
- Build-tree visualization: commands such as
nh osuse nix-output-monitor (nom) to make the build dependency tree clear at a glance. - Change comparisons: integrated, ultrafast derivation diffs before activation or switching.
- Build-tree visualization: commands such as
- Specialisation support: easily select or ignore NixOS and Home-Manager specialisations through command arguments.
- Generation management: inspect, roll back, and manage system generations, with support for selecting a specific target generation.
- Extensible and future-ready: designed to make adding new subcommands and arguments quick and seamless.
- nh reimplements the CLI tools you know and love, with a stronger emphasis on safety and correctness. Its language and design choices make new features easy to add with virtually no overhead.
- Excellent documentation: everything nh can do is documented. Everything nh does is documented too. User and developer documentation is always kept up to date.
Design philosophy
nh is a _unified_ CLI, meaning that it aims to bring core platform support together in one convenient tool. Its interface currently supports NixOS as a first-class platform, Home Manager, and Nix-Darwin. We want to give users of these projects a familiar, convenient, and _beautiful_ interface.
nh’s interface may look familiar, but that should not be seen as a weakness: nh is not a wrapper around nixos-rebuild and is not constrained by tools of that kind. In short, we aim not only to _implement existing functionality_, but to _go beyond it_, adding commands and arguments that improve the experience provided by the default tools. That means _infrastructure_ and _sensible defaults_ matter. You can enjoy the tools you are used to while gaining the benefits of a faster, safer language.
Future goals for nh include support for lower-level tools such as
nixos-installandnixos-generate-config, making it a Rust alternative to most core tools. Feedback and feature requests are welcome on the Discussions and Issues pages.
Current status#
The release and backport descriptions below come from the notes’ snapshot. Check the pinned Nixpkgs for actual stable package versions and backport availability.
nh is packaged in nixpkgs and is available in both nixpkgs stable and nixpkgs unstable. The original upstream translation describes its backport policy, but this should not be taken as a guarantee that every update reaches stable. See the Installation section for details. If the package is out of date, please submit an update request.
Installation
The latest tagged release is available in Nixpkgs as nh stable and is recommended for most users, since tagged releases generally receive more testing. This repository also provides the latest development version of nh through its flake outputs.
nix shell nixpkgs#nh # 稳定版
nix shell github:nix-community/nh # 开发版You can try nh in a Nix shell right now, with no configuration required!
NixOS
We provide a NixOS module to run nh clean as a system service. Enable it as follows:
{
programs.nh = {
enable = true;
clean.enable = true;
clean.extraArgs = "--keep-since 4d --keep 3";
flake = "/etc/nixos"; # NixOS 模块设置 NH_FLAKE
};
}programs.nh module configuration reference#
nh (Nix Helper) is a tool designed to simplify Nix and NixOS command-line operations. The programs.nh module lets you declaratively install it, set a default Flake path, and configure automatic system cleanup tasks based on nh.
Option list
programs.nh.enable
- Type: boolean (
Boolean) - Default:
false - Description: whether to enable
nhand its associated configuration. When set totrue, the system installs thenhpackage into the global environment.
programs.nh.package
- Type: Nix package (
Package) - Default:
pkgs.nh - Description: the
nhpackage instance to install. The default is usually sufficient; override it here if you need a specific version or a custom build ofnh.
programs.nh.flake
- Type: null or a single-line string (
null or string) - Default:
null - Description: the default Flake path for
nh. This value is assigned to theNH_FLAKEenvironment variable and supplies the default Flake reference for commands such asnh os switch. - Override mechanism: you can override this default for specific commands by setting the following environment variables:
NH_OS_FLAKE: takes precedence fornh oscommands.NH_HOME_FLAKE: takes precedence fornh homecommands.NH_DARWIN_FLAKE: takes precedence fornh darwincommands.
- Constraint: this path must point to a directory, not an individual
.nixfile. An invalid configuration triggers an assertion error during the system build.
programs.nh.clean.enable
- Type: boolean (
Boolean) - Default:
false - Description: whether to enable periodic garbage collection based on
nh clean all. - Important: if this option is enabled, you must disable the system’s native
nix.gc.automatic = true; otherwise, the two scheduled jobs conflict and trigger a system warning at build time.
programs.nh.clean.dates
- Type: single-line string (
singleLineStr) - Default:
"weekly" - Description: how often the cleanup task runs. This string is passed to
systemd.time. - Format reference: accepts the time formats defined in
systemd.time(7), such as"weekly","daily", or a specific time such as"03:30".
programs.nh.clean.extraArgs
- Type: single-line string (
singleLineStr) - Default:
"" - Description: extra arguments passed to
nh clean allwhen the automatic cleanup service runs. - Example:
"--keep 5 --keep-since 3d"(keep the most recent 5 generations and all generations from the last 3 days). Consultnh clean all --helpfor available arguments.
Configuration example
The following shows a standard configuration.nix example that enables and configures nh:
{ config, lib, pkgs, ... }:
{
# 启用 nh 工具
programs.nh = {
enable = true;
# 指定默认的 Flake 路径,简化日常命令
flake = "/etc/nixos";
# 配置 nh 接管系统的自动垃圾回收
clean = {
enable = true;
dates = "weekly"; # 每周执行一次
# 保留策略:至少保留最近 5 个世代,且近 7 天内的世代全部保留
extraArgs = "--keep 5 --keep-since 7d";
};
};
# 关键:禁用原生 nix.gc 以避免与 nh 的清理任务冲突
nix.gc.automatic = lib.mkForce false;
}Starting with version 4.0, nh fully supports both Nix flakes and traditional NixOS configurations managed through channels or manual dependencies. Treat the new API as mature but still somewhat experimental. Bug reports are welcome!
- For flakes, use
nh os switch /path/to/flake- For traditional configurations:
nh os switch -f '<nixpkgs/nixos>', ornh os switch -f '<nixpkgs/nixos>' -- -I nixos-config=/path/to/configuration.nix(if you use a non-default path)
Check nh os --help or man 1 nh for other arguments and environment-variable defaults.
Specialisation support
nh can detect which specialisation you are currently running and execute the correct activation script. To do so, tell nh by writing the specialisation’s name to /etc/specialisation:
{config, pkgs, ...}: {
specialisation."foo".configuration = {
environment.etc."specialisation".text = "foo";
# ..其余配置
};
specialisation."bar".configuration = {
environment.etc."specialisation".text = "bar";
# ..其余配置
};
}Home-Manager
Home specialisations are read from ~/.local/share/home-manager/specialisation. Configure this as follows:
{config, pkgs, ...}: {
specialisation."foo".configuration = {
xdg.dataFile."home-manager/specialisation".text = "foo";
# ..其余配置
};
specialisation."bar".configuration = {
xdg.dataFile."home-manager/specialisation".text = "bar";
# ..其余配置
};
}Usage#
One of nh’s core principles is to give users a clear, unified, and intuitive CLI experience. The nh command offers multiple subcommands, each with a rich set of CLI arguments for flexible configuration.
nh supports a variety of arguments, environment variables, and configuration options to provide the best possible user experience. Consult each subcommand’s
--helppage orman 1 nhfor more details and examples. You can also customize it for your system through the relevant platform’s module, such as the NixOS module in Nixpkgs, as described in the installation section.
Under the nh command, you will use two categories of commands:
Global subcommands
Global subcommands enhance core Nix commands. We currently offer better search and better garbage collection through two ready-to-use subcommands.
nh search
We provide ultrafast Nix package and NixOS/Home Manager option search, powered by the search.nixos.org Elasticsearch backend, as well as offline search of local SPAM databases and searches for Nixpkgs pull requests and issues. All are available through nh search! These extended search subcommands belong to the feature snapshot recorded in the notes; if your distribution’s nh search --help does not list them, do not assume they are available.
The notes list the following search modes and convenient shorthand forms:
| Invocation | Function |
|---|---|
nh search <query> |
Shorthand form; searches packages by default (change the default with NH_DEFAULT_SEARCH) |
nh search packages <query> |
Search Nixpkgs packages through search.nixos.org |
nh search options [--scope=<SCOPE>] <query> |
Search NixOS/Home Manager options (--scope: nixpkgs, home-manager, all) |
nh search offline --db <PATH> <query> |
Search local SPAM databases offline. Obtain a pre-generated database matching your machine from the upstream SPAM project. |
nh search prs [--days <DAYS>] <query> |
Search Nixpkgs pull requests and show branch reachability for merged PRs. Defaults to the last 15 days. |
nh search issues [--days <DAYS>] <query> |
Search Nixpkgs issues, excluding pull requests. Defaults to the last 15 days. |
--json is available in every search mode. --limit, --channel, and --platforms are available in the search modes and shorthand forms to which those arguments apply.
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 you for one and saves it to the token file.
nh clean
A reimplementation of nix-collect-garbage that also cleans gcroots, offers options for fine-grained control over what to retain, and shows additional information before cleanup so you can see what will be removed.
In the source version, gcroots cleanup in
nh cleaninspects your gcroots directory. Removing the corresponding roots leaves build results or direnv caches unprotected; it does not guarantee deletion of all project directories. Check the default switches and cleanup scope with your locally installednh clean --help.Use
--no-gcrootsto skip all gcroot cleanup, or--no-direnvto preserve direnv gcroots while cleaning everything else.
Platform-specific subcommands
Platform-specific subcommands implement CLI tools for NixOS, Home Manager, and Nix-Darwin.
nh os
The nh os subcommand reimplements the Python script nixos-rebuild-ng[^1] from scratch, and additionally provides:
- Build-tree visualization through nix-output-monitor (nom)
- Attractive change diffs through dix
- Confirmation prompts
And other interface improvements, from environment-variable support to extra safety measures. Is that all? No, there is more to look forward to.
nh home
The nh home subcommand reimplements the home-manager script with the same enhancements as nh os.
nh darwin
Last but not least, the nh darwin subcommand is a pure Rust reimplementation of the darwin-rebuild script, with the same enhancements as nh os and nh home.
Command examples
| Platform | Old command (without nh) | New command (with nh) |
|---|---|---|
| NixOS | nixos-rebuild switch --flake .#workstation |
nh os switch . -H workstation |
| Darwin | darwin-rebuild switch --flake .#workstation |
nh darwin switch . -H workstation |
| Home Manager | home-manager switch --flake .#workstation |
nh home switch . -c user |
If NH_FLAKE is set, nh lets you omit the flake path. The NixOS and Home-Manager modules set this automatically when programs.nh.flake is configured.
nh also lets you omit the NixOS/Darwin hostname (-H) and Home Manager configuration name (-c) when the system can discover them automatically. For example, with NH_OS_FLAKE set, you can simply run nh os switch without extra arguments, and it automatically resolves nixosConfigurations.<workstation>.
nh also allows the Nix file path to be omitted for non-flake configurations. You can specify the Nix file and Nix attribute path with the NH_FILE and NH_ATTRP environment variables. If both NH_FILE and NH_ATTRP are set, nh os switch effectively operates on $NH_FILE#$NH_ATTRP.
Environment variables#
Some variables come from development-branch documentation; check support against the installed nh version. Variable names are not credentials, and no token values are included here.
nh supports various environment variables that control command behavior. The following are common variables you may encounter or choose to use:
Global
NIX_SSHOPTS,NIX_CONFIG, andNIX_REMOTEare forwarded to all Nix commands run with environment isolation.NIX_SSL_CERT_FILE- Specifies a TLS CA certificate file for Nix; it has nothing to do with bootloader installation.
NIX_USER_CONF_FILES- Specifies the list of Nix configuration files read by the client.
NIXOS_INSTALL_BOOTLOADER- Relates to reinstalling the bootloader during system activation; do not confuse it with TLS configuration. Check its accepted values and activation-script behavior against the system version.
NH-specific
NH_NO_CHECKS- When set to a nonempty value, skips startup checks such as Nix version and experimental-feature verification. Useful for generating completions or running in constrained build environments. You can also think of it as "expert mode", offering a small performance gain, provided you know what you are doing.
NH_FLAKE- The preferred path/reference to the directory containing
flake.nixthat NH uses for flake-based commands. Its historical predecessor wasFLAKE; if the platform-specificNH_*_FLAKEis unset andFLAKEexists, NH migrates it toNH_FLAKE.
- The preferred path/reference to the directory containing
NH_OS_FLAKE、NH_HOME_FLAKE、NH_DARWIN_FLAKE- Flake references for the
os,home, anddarwincommands, respectively. When present, they take precedence overNH_FLAKE.
- Flake references for the
NH_SUDO_ASKPASS- The path to the helper invoked when NH elevates privileges with
sudo. IfSUDO_ASKPASSis set, NH passes-Atosudo.
- The path to the helper invoked when NH elevates privileges with
NH_PRESERVE_ENV- Controls whether environment variables marked for preservation are passed to elevated commands. Set to
"0"to disable preservation or"1"to force it. If unset, preservation is enabled by default.
- Controls whether environment variables marked for preservation are passed to elevated commands. Set to
NH_SHOW_ACTIVATION_LOGS- Controls whether activation output is shown. Activation output is hidden by default. Setting this to
"1"shows full activation logs to help debug activation failures. Supported on all platforms: NixOS, Home Manager, and Darwin.
- Controls whether activation output is shown. Activation output is hidden by default. Setting this to
NH_LOG- Sets NH’s logging/tracing filter. Uses the same format as the
tracing_subscriberenvironment filter, for examplenh=trace.
- Sets NH’s logging/tracing filter. Uses the same format as the
NH_CONFIG- Overrides the NH configuration-file path. If unset, NH uses
$XDG_CONFIG_HOME/nh/config.toml, falling back to~/.config/nh/config.toml.
- Overrides the NH configuration-file path. If unset, NH uses
GH_TOKEN- The GitHub token used by
nh search prsandnh search issues. When set, it takes precedence over any token file.
- The GitHub token used by
NH_GITHUB_TOKEN_FILE- Overrides the GitHub token-file path used by
nh search prsandnh search issueswhenGH_TOKENis unset. If this variable is unset, NH uses$XDG_STATE_HOME/nh/github-token, falling back to~/.local/state/nh/github-token. Tokens entered at the interactive prompt are saved to this file with permissions allowing only the user to read it.
- Overrides the GitHub token-file path used by
NH_SEARCH_CHANNEL- The default Nixpkgs channel used by
nh search packagesandnh search options, such asnixos-unstable. Override it for an individual invocation with--channel.
- The default Nixpkgs channel used by
NH_SEARCH_JSON- When set to a truthy value,
nh searchoutputs results as raw JSON instead of a formatted display. Equivalent to--json.
- When set to a truthy value,
NH_SEARCH_PLATFORM- When set to a truthy value, shows the supported platforms for each package result. Equivalent to
--platforms.
- When set to a truthy value, shows the supported platforms for each package result. Equivalent to
NH_DEFAULT_SEARCH- Controls the target of the
nh search <query>shorthand form when no subcommand is specified. Accepted values arepackages(default),options, andall. Equivalent to--default-search.
- Controls the target of the
NH_OFFLINE_DB- A colon-separated list of SPAM database file paths for
nh search offline. Each path is treated as an independent database. Equivalent to passing--dbmultiple times. Example:NH_OFFLINE_DB=/var/cache/spam/nixpkgs.db:/var/cache/spam/hm.db.
- A colon-separated list of SPAM database file paths for
NH_NOM- Controls whether nom (nix-output-monitor) is enabled during builds. Equivalent to
--no-nom.
- Controls whether nom (nix-output-monitor) is enabled during builds. Equivalent to
NH_REMOTE_CLEANUP- Whether to try cleaning up remote processes through pkill on interruption. This feature matches nixos-rebuild’s behavior, but is disabled by default because it is inherently fragile. Usually unnecessary unless NH leaves zombie processes behind after an interruption.
Notes
- NH explicitly propagates any environment variable prefixed with
NH_to subcommands where appropriate, that is, during environment isolation. - For backward compatibility, if
FLAKEexists and no platform-specificNH_*_FLAKEvariable is set, NH setsNH_FLAKEto the value ofFLAKEand prints a migration warning.FLAKEwill be removed in a future version of NH.
Frequently asked questions (FAQ)#
Q: does nh wrap the CLI tools I normally use?
A: no. All commands invoke Nix directly; they do not use the traditional CLI tools. nh is gradually replacing tools formerly invoked through a shell with native Rust libraries for safer integration and slightly better performance.
Contributing#
Contributions are welcome. Simply clone the repository and run nix develop. We also provide an .envrc for Direnv users; run direnv allow to enter the development environment.
[^1]:nixos-rebuild-ng does not yet have complete feature parity with nixos-rebuild. Although many subcommands have been implemented, some features may still be missing. See #358 for the roadmap.
Structure
The following src/xtask description preserves the code layout in the older translation. The current repository may have been split into directories such as crates and docs; read the current CONTRIBUTING documentation before contributing.
nh is written in Rust and consists of two modules. The core code is in src, divided into submodules. Key modules to know include nh::commands for the command interface, nh::checks for pre-startup checks, and nh::util for shared logic. Platform-specific logic lives in the corresponding platform module, such as nh::nixos or nh::darwin, while general helper functions live in nh::util.
The xtask directory contains the cargo-xtask tasks NH uses for work such as generating manpages.
Submitting changes
After making changes, remember to run just fix to apply the general formatting and lint rules expected by CI.
Before creating your change, you also need to update the changelog with enough information to describe the new behavior.
This may look daunting, but it is not. Even if you _do not_ meet these requirements, you will receive friendly guidance to finish the changes. Friendly contributions are always welcome.
Acknowledgments
nh has a long history and has grown considerably over the years. The original translation recounts the project’s history in NotAShelf’s voice, beginning with thanks to ViperML for his tremendous work as nh’s creator and first maintainer. I recently took over nh, but none of this would have been possible without him.
Next, I want to thank the tools we use under the hood. Upgrade-diff visualization comes from my good friend faukah’s dix crate. Compared with our previous diff tool, nvd, dix is more than twice as fast, a boon for nh’s diff experience. Thank you!
nix-output-monitor is another excellent tool worth mentioning. nh uses it under the hood to display beautiful build trees. Many thanks to nix-output-monitor for giving countless nh users like me such attractive build visualization.
I also want to thank the many Rust crates that power nh under the hood and give it its distinctive UX. Without the wonderful Rust ecosystem, nh would not be where it is today.
Last but not least, I want to thank… you! Thank you to everyone who contributes to nh, discusses it, or criticizes it to drive improvements. nh would not be where it is today without you.
Order of operations: build, activate, and clean#
For system commands, you can start with nh os build to check the build result. nh os test still actually activates services, while nh os switch changes the running system and default configuration. nh clean reduces the generations and caches available for recovery; use it only after confirming retention time, generation count, and gcroots scope. NixOS’s programs.nh.flake sets NH_FLAKE, while platform-specific variables such as NH_OS_FLAKE take precedence; do not conflate them. The upstream module source confirms that enabling both clean and the native nix.gc automatic task produces a warning. Choose one timer.
References & further reading
- Upstream nh project ↗
- NixOS nh module source ↗
- SPAM project ↗
- nh README: pinned reference for this license verification ↗
- nh: EUPL-1.2 license at the reference revision ↗
- Full EUPL-1.2 license ↗
- Editable source of this article ↗
Adapted from technical notes. Examples use generic names.
Continue along a reading path
Nix commands and long-term maintenance
- 01A NixOS learning roadmap: foundations, Flakes, user configuration, and beyond
- 02Nix commands explained: builds, environments, profiles, and systems
- 03nh: a unified workflow for Nix systems, users, and cleanup
- 04Garbage collection, store optimization, and rollback generations
- 05NixOS configuration organization, maintenance, and troubleshooting