Introduction - nixos-cli

nixos-cli is a robust, cohesive, drop-in replacement for NixOS tooling such as nixos-rebuild, among many other tools.

Why?

NixOS tooling today is fragmented across large, aging shell and Perl scripts that are difficult to maintain or extend. Prolific examples include:

These tools contain deep functionality, but much of it is hidden, hard to modify, or locked behind poor ergonomics.

nixos-cli aims to modernize this experience by:

  • Replacing and improving existing tooling
  • Providing a consistent interface across all commands
  • Making functionality more accessible and extensible
  • Offering a clean, discoverable CLI experience for both users and developers

In summary, this tool has one goal: to create a modular NixOS CLI that mirrors or enhances the functionality of all current NixOS tooling in nixpkgs, adds on to it if needed, and eventually come to replace it entirely.

Yes, this is already being done somewhat by switch-to-configuration-ng and nixos-rebuild-ng. However, nixos-cli strives to achieve further goals, including (but not limited to the following)

  • Enhanced usability (and looking nice! Who doesn't love eye candy?)
  • Deeper integration with NixOS internals
  • Creating a self-contained NixOS manager binary that includes routine scripts such as switch-to-configuration activation functionality
  • Plugins for further NixOS tooling to be developed out-of-tree

Key Features

  • Drop-in replacements for common NixOS tools (with better names!)
  • An integrated NixOS option search UI
  • An improved generation manager, with an additional UI (more fine-tuned than nix-collect-garbage -d)

Check out the overview page for more information about key features.

More features are planned; see the roadmap for more information.

Status

This tool is under active development, but is not yet stable.
Until a 1.0 release, the CLI interface and configuration may change without notice.

Watch the Releases page for:

  • Breaking changes
  • Feature updates
  • Bug fixes

Core contributors:

Contributions, testing, and bug reports/general feedback are highly encouraged, since there are few people working on this project actively.

Talk!

Join the Matrix room at #nixos-cli:matrix.org! It's open for chatting about NixOS in general, and for making it a better experience for all that involved.

Installation

nixos-cli is split into two separate executables. This is very intentional for a number of reasons.

  1. The majority of NixOS users use either flakes or legacy-style Nix, without mixing the two.
  2. While the majority of logic is shared between the two styles of configuration, the command-line interface should not be forced to deal with the differences, for the sake of clarity.
  3. If users want to mix styles, they should do so intentionally. This distinction is reflected in the CLI binaries themselves—not hidden in command behavior.

The flake-style configuration is the default. Nix flakes have been available for several years; although still technically experimental, they are widely adopted and considered stable in practice, particularly in forks like Lix. Legacy configurations are actively supported regardless of this status, though.

NixOS has quite a large ecosystem of tools, and can be quite the moving target in terms of features, so nixos-unstable and the current stable release are the only actively supported releases.

Adding To Configuration

Use the following sections depending on whether or not your systems are configured with flakes or legacy-style configurations.

Available configuration settings for nixos-cli are defined in the more detailed settings section, and are specified in Nix attribute set format here. Internally, they are converted to TOML.

Flakes

nixos-cli is provided as a flake input. Add this and the exported NixOS module to the system configuration.

{
  inputs.nixos-cli.url = "github:nix-community/nixos-cli";

  outputs = { nixpkgs, nixos-cli, ... }: {
    nixosConfigurations.system-name = nixpkgs.lib.nixosSystem {
      modules = [
        nixos-cli.nixosModules.nixos-cli
        # ...
      ];
    };
  };
}

Then, enable the module.

{ config, pkgs, ... }:

{
  services.nixos-cli = {
    enable = true;
    config = {
      # Whatever settings desired.
    }
  };
}

The default package is flake-enabled, so the services.nixos-cli.package option does not need to be specified.

Legacy

To use the NixOS module in legacy mode, import the default.nix provided in this repository. An example is provided below with builtins.fetchTarball:

{ config, system, pkgs, ...}:

let
  # In pure evaluation mode, always use a full Git commit hash instead of a branch name.
  nixos-cli-url = "github:nix-community/nixos-cli/archive/GITREVORBRANCHDEADBEEFDEADBEEF0000.tar.gz"
  nixos-cli = import "${builtins.fetchTarball nixos-cli-url}" {inherit pkgs;};
in {
  imports = [
    nixos-cli.module
  ];

  services.nixos-cli = {
    enable = true;
    package = nixos-cli.nixosLegacy;
    config = {
      # Other configuration for nixos-cli
    };
  };

  # ... rest of config
}

NOTE: Use the nixosLegacy package. Specifying the services.nixos-cli.package option is required for legacy configurations, due to the fact that the default package is for flake configurations only. If there is a reliable way to detect if a configuration is flake-enabled, please file an issue so that this requirement can be removed.

Cache

There is a Cachix cache available. Add the following to your NixOS configuration to avoid lengthy rebuilds and fetching extra build-time dependencies:

{
  nix.settings = {
    substituters = [ "https://watersucks.cachix.org" ];
    trusted-public-keys = [
      "watersucks.cachix.org-1:6gadPC5R8iLWQ3EUtfu3GFrVY7X6I4Fwz/ihW25Jbv8="
    ];
  };
}

Or if using the Cachix CLI outside a NixOS environment:

$ cachix use watersucks

There are rare cases in which you want to automatically configure a cache when using flakes, such as when installing NixOS configurations using this tool. The following configuration in the flake.nix can help with this:

{
  nixConfig = {
    extra-substituters = [ "https://watersucks.cachix.org" ];
    extra-trusted-public-keys = [
      "watersucks.cachix.org-1:6gadPC5R8iLWQ3EUtfu3GFrVY7X6I4Fwz/ihW25Jbv8="
    ];
  };

  inputs = {}; # Whatever you normally have here
  outputs = inputs: {}; # Whatever you normally have here
}

⚠️ Beware, though: this is a relatively undocumented feature—use with caution.

Running Using Nix Shells

Sometimes, you may not want to add it to your configuration, and instead run nixos-cli on an ad-hoc basis.

This is the preferred way to use nixos-cli when running nixos init or nixos install on a live NixOS USB for installation.

Use nix develop (flake-enabled package by default):

$ nix shell github:nix-community/nixos-cli

Alternative using legacy-style nix-shell and the nixosLegacy package:

$ nix-shell -E 'with import (fetchTarball "https://github.com/nix-community/nixos-cli/archive/refs/heads/main.tar.gz") {}; nixosLegacy'

Rebuild

After adding the next sections to your configuration, rebuild your configuration once, and then the nixos command should be available. Verify by running nixos features:

# Example output of `nixos features`
$ nixos features
nixos 0.13.0-dev
git rev: 53beba5f09042ab8361708a5e0196098d642ba5b
go version: go1.24.1
nix version: nix (Nix) 2.28.2

Compilation Options
-------------------
flake           :: true
nixpkgs_version :: 24.11

Nice! nixos-cli is now ready for usage.

Overview

NixOS Tooling Replacements

nixos-cli has drop-in replacements for the following tools:

  • nixos-rebuildnixos apply + nixos generation
  • nixos-enternixos enter
  • nixos-generate-confignixos init
  • nixos-versionnixos info
  • nixos-installnixos install
  • nixos-infonixos manual

nixos apply + nixos generation

nixos-rebuild is primarily used to manage NixOS configurations, but has become bloated and has some non-obvious behavior.

nixos-rebuild commands are replaced entirely by a combination of the nixos apply and nixos generation commands, with some better-looking logging, showing diffs between generations, and interactive confirmation before applying configurations.

Alternatives to builtin Nix tools are provided that can be switched through the settings if available; for example:

A list of analogues to nixos-rebuild behavior:

# `nixos-rebuild switch`
$ nixos apply

# `nixos-rebuild switch`, without interactive confirmation
$ nixos apply -y

# `nixos-rebuild switch` on an arbitrary flake ref
$ nixos apply "github:water-sucks/nixed#CharlesWoodson"

# `nixos-rebuild test`
$ nixos apply --no-boot

# `nixos-rebuild vm[-with-bootloader]`
$ nixos apply --vm[-with-bootloader] --output ./vm

# `nixos-rebuild boot`
$ nixos apply --no-activate

# `nixos-rebuild list-generations`
$ nixos generation list

# Show diffs between two generation numbers on the local system
$ nixos generation diff 59 60

# Switch to an arbitrary generation number (and specialisation)
$ nixos generation switch 420 [--specialisation "wayland"]

# `nixos-rebuild switch --rollback`
$ nixos generation rollback

# Fine-tuned generation deletion; keep at least five generations, delete the rest
$ nixos generation delete --min 5 --all

Check the manual for more important information.

Setting the $NIXOS_CONFIG variable allows for not specifying the --flake flag at all, which is a huge improvement over nixos-rebuild.

nixos generation list by default is a TUI list with Vim-like bindings. To get tabular, grep-able output like the old behavior of nixos-rebuild uses, use -t.

Default specialisations are managed through the nixos-cli configuration.

In the future, setting build and target hosts for remote building/activation using SSH will be supported.

nixos-enter

nixos enter behaves mostly the same as nixos-enter, minus some extra logging controls.

nixos-generate-config -> nixos init

nixos init can be used in the same way as nixos-generate-config. Usually, this is done through a NixOS live USB before installation. As such, refer to the installation section for instructions on how to do that.

NOTE: The current configuration that is generated does not include nixos-cli setup, due to implementation complexity. If you believe this is important enough, please file a feature request.

nixos-install -> nixos install

nixos install can also be used in the same way as the current nixos-install script. Similar to nixos init usage, this is likely to be done off a live USB, rather than on a live system.

In the future, remote NixOS installations will be supported.

nixos features

This command describes the features that nixos-cli was compiled with.

Use this when filing issues, in order to provide information about the environment for proper problem diagnosis.

Option UI

The option UI is a nice search for NixOS options that are available on a given system. These are computed on demand for the system, so all available options on that exact system are present.

This is a significant advantage over alternatives; since options are computed from the modules present in a given system, modules that don't have module documentation exposed can still have documentation through the option UI!

Cool, right?

Run nixos option -i for the interactive search TUI.

Also, nixos option will just print options and their evaluated values, without dropping into a TUI.

However, there is one caveat: generating the option index is an intensive operation; this can be precomputed on every configuration change using the services.nixos-cli.prebuildOptionCache if desired.

Environment Variables

The following environment variables influence nixos-cli behavior:

  • NO_COLOR :: disable output color (does not apply for TUIs)

  • NIXOS_CLI_CONFIG :: change the nixos-cli settings location (default: /etc/nixos-cli/config.toml)

  • NIXOS_CONFIG :: where the configuration to work with is stored

    This can vary depending on if the CLI is flake-enabled. If the CLI is flake-enabled, then $NIXOS_CONFIG must point to a valid flake ref. Otherwise, it can point to a local Nix configuration file (i.e. configuration.nix) or directory containing a default.nix.

Aliases

Aliases can be used to make shortcuts for nixos-cli commands. Check the settings section for an example.

A list of common aliases that people can configure:

  • nixos genlist :: nixos generation list
  • nixos switch :: nixos generation switch
  • nixos testcfg :: nixos apply --no-boot --no-activate
  • nixos build :: nixos apply --no-boot --no-activate --output ./result

NOTE: Currently, aliases to compose multiple CLI commands or to invoke shell commands are not supported. If this is important to you, please file a feature request.

Completion

Shell completion is provided through the default package. Descriptions for completion candidates are provided (requires newer Bash versions if applicable).

If desired, completion scripts can be obtained manually using nixos completion <SHELL>.

Supported shells:

  • bash
  • zsh
  • fish

If you want support for another shell, file an issue. However, this support is provided by Cobra, and as such, support will probably need to be implemented upstream before this is possible.

Settings

Settings are stored in /etc/nixos-cli/config.toml, and are stored in TOML format.

If preferred, this can be overridden by an environment variable NIXOS_CLI_CONFIG at runtime. This is useful for testing configuration files.

Additionally, some configuration values can be overridden on the command-line with the --config flag.

Example invocation:

$ nixos --config apply.imply_impure_with_tag=false apply

The preferred way to create this settings file is through the provided Nix module that generates the TOML using the services.nixos-cli.config option. Refer to the module documentation for other available options.

Available Settings

These are the available settings for nixos-cli and their default values.

General

  • aliases

    Defines alternative aliases for long commands to improve user ergonomics. Example:

[aliases]
genlist = ["generation", "list"]
switch = ["generation", "switch"]
rollback = ["generation", "rollback"]

Default: []

  • auto_rollback

    Enables automatic rollback of a NixOS system profile when an activation command fails. This can be disabled when a reboot or some other circumstance is needed for successful activation

    Default: true

  • color

    Turns on ANSI color sequences for decorated output in supported terminals.

    Default: true

  • config_location

    Path to a Nix file or directory to look for user configuration in by default.

    Default: "/etc/nixos"

  • no_confirm

    Disables prompts that ask for user confirmation, useful for automation.

    Default: false

  • root_command

    Specifies which command to use for privilege escalation (e.g., sudo or doas).

    Default: "sudo"

  • use_nvd

    Use the better-looking nvd diffing tool when comparing configurations instead of nix store diff-closures.

    Default: false

apply

Settings for apply command

  • apply.ignore_dirty_tree

    Allows 'apply' to use Git commit messages even when the working directory is dirty.

    Default: false

  • apply.imply_impure_with_tag

    Automatically appends '--impure' to the 'apply' command when using '--tag' in flake-based workflows.

    Default: false

  • apply.specialisation

    Specifies which systemd specialisation to use when activating a configuration with 'apply'.

    Default: ""

  • apply.use_git_commit_msg

    When enabled, the last Git commit message will be used as the value for '--tag' automatically.

    Default: false

  • apply.use_nom

    Enables nix-output-monitor to show more user-friendly build progress output for the 'apply' command.

    Default: false

enter

Settings for enter command

  • enter.mount_resolv_conf

    Ensures internet access by mounting the host's /etc/resolv.conf into the chroot environment.

    Default: true

init

Settings for init command

  • init.desktop_config

    Specifies the desktop environment configuration to inject during initialization.

    Default: ""

  • init.extra_attrs

    Default: []

  • init.extra_config

    Default: ""

  • init.xserver_enabled

    Controls whether X11-related services and packages are configured by default during init.

    Default: false

option

Settings for option command

  • option.debounce_time

    Controls how often search results are recomputed when typing in the options UI, in milliseconds.

    Default: 25

  • option.min_score

    Sets the cutoff score for showing results in fuzzy-matched option lookups.

    Default: 1

  • option.prettify

    If enabled, renders option documentation in a prettier Markdown format where applicable.

    Default: true

Module

These are the available NixOS module options for nixos-cli. This is the preferred way to configure things like settings, and to add the CLI itself to the $PATH.

services.nixos-cli.enable

unified NixOS tooling replacement for nixos-* utilities

Type: boolean

Default: false

Example: true

services.nixos-cli.package

Package to use for nixos-cli

Type: types.package

Default: self.packages.${pkgs.system}.nixos

services.nixos-cli.config

Configuration for nixos-cli, in TOML format

Type: tomlFormat.type

Default: {}

services.nixos-cli.generationTag

A description for this generation

Type: types.nullOr types.str

Default: lib.maybeEnv "NIXOS_GENERATION_TAG" null

Example: "Sign Git GPG commits by default"

services.nixos-cli.prebuildOptionCache

Prebuild JSON cache for nixos option command

Type: types.bool

Default: config.documentation.nixos.enable


Generated with nix-options-doc

FAQ

Do you intend on making this an official NixOS application?

Yes! I will be writing an RFC to see if people are interested in this.

That's my ultimate goal, anyway.

What about nh? Isn't that better since it supports more OSes?

nh is a more popular application in this realm, perhaps because it looked prettier due to the earlier nix-output-monitor and nvd integration, and is significantly older than nixos-cli.

However, I prefer to keep the focus on NixOS here, while nh tries to be a unified rebuild + switch manager for multiple OSes. That's the difference.

nixos-cli also has more features than nh for NixOS-based machines, so that's a plus.

What about home-manager and nix-darwin? Will you support those systems?

They are fundamentally separate projects with roughly similar surfaces, so no. I am a heavy user of both projects, though, so I may write my own darwin and hm CLIs that roughly mirror this.

Think about this:

  • home-manager has to work in the user context, while NixOS works in the system one.
  • nix-darwin doesn't interact with boot scripts, while NixOS does.

Among a slew of other differences. The rebuild + switch workflow may be the same, but the options are different, and I'm lazy. So no.

Can the option search work with other sources?

It's theoretically possible, as long as the modules can be evaluated with lib.evalModules. As such, home-manager, nix-darwin, and even flake-parts are possible to do!

However, this tends to significantly increase evaluation time, and will depend on the system to eval. I plan to break out the option search UI into a separate project that can be more generalized, and add it back to this one as a plugin of sorts.

More questions?

File an issue! Perhaps it's important enough to add to this FAQ as well.

Contributing

Contributions of all kinds are appreciated! The following are especially welcome.

Code Contribution

This is by far the best way to help!

nixos-cli is quite a large tool with a very large scope and many moving parts, so any efforts to ease the burden around implementation and maintenance is greatly appreciated. Even so-called "drive-by" contributions or features are also appreciated, as long as they do not result in excessive maintenance burden later on.

Submit contributions through pull requests, or by emailing them personally to varun@snare.dev, if you do not want to use GitHub. Credit will be preserved.

Please make sure your code is up to standard by running:

  • gofmt to format Go code
  • golangci-lint to catch common issues
  • prettier to format Markdown files

All available dependencies are provided in a Nix development shell.

If your changes modify the CLI or any core behavior, please also update the relevant man pages or documentation in doc/. This includes changes to the following things:

  • CLI commands/options
  • Settings
  • NixOS module options

Bug Reports

Testing every feature edge-case is hard—especially before full releases.

If you're a brave soul, use the main branch instead of a release version, and file bug reports by opening a new issue with the Bug Report template. In the bug report, provide:

  • A clear description of the problem
    • IMPORTANT: What was expected vs. what actually happened
  • Steps to reproduce the issue
  • Your environment (run nixos features)
  • Any relevant logs, error messages, or images

Clear reports will assist in faster bug fixes!

Improving Documentation

Nix documentation is notoriously patchy — so help here is especially welcome.

As such, documentation quality is of utmost importance. nixos-cli should be a tool that is both easy to use and powerful in functionality; however, as powerful as it can be, who cares if that power isn't discoverable?

Documentation lives in two places:

  • Markdown files for this website, generated using mdbook
  • Manual pages (man pages), generated using scdoc

Refer to the code contribution guidelines when submitting documentation improvements, or file an issue if the documentation issues are substantial.

Feature Suggestions

Have an idea for improving NixOS tooling here? Start a discussion or open an issue!

Discourse around how this can be done is always productive.

The vision is to make this a standard NixOS tool, so all ideas that align with that scope are welcome. If there’s a new command or sub-tool you’d like to see, open a GitHub issue or reach out on Matrix. However, try to keep it within scope of the NixOS project, though.

❌ Features like home-manager or nix-darwin integration will not be considered as first-class features. Sorry in advance.

Community Conduct

All contributors must follow a friendly, respectful code of conduct.

The TL;DR? Don't be a dick.

Disagreement is fine, but harassment, rudeness, or discrimination are not tolerated in any spaces.

Roadmap

  • ❌ Remote application of configurations
  • ❌ Remote installation of NixOS configurations (a la nixos-anywhere)
  • ❌ Ability to remotely manage generations
  • ❌ Smart container management (a la nixos-container)
  • ❌ Explicit ability to deploy systems from non-NixOS operating systems
  • Drafting an RFC to make nixos-cli the default NixOS management tool

See the Issues section in the GitHub repository for a list of other issues and/or features to be implemented or make your own requests! All requests are welcome.