[[ch-nix-flakes]]
== Nix Flakes

:nixos-wiki-flakes: https://nixos.wiki/wiki/Flakes

Home Manager is compatible with {nixos-wiki-flakes}[Nix Flakes]. But
please be aware that the support it is still experimental and may
change in backwards incompatible ways.

Just like in the standard installation you can use the Home Manager
flake in three ways:

1. Using the standalone `home-manager` tool. For platforms other than
NixOS and Darwin, this is the only available choice. It is also
recommended for people on NixOS or Darwin that want to manage their
home directory independently of the system as a whole. See
<<sec-flakes-standalone>> for instructions on how to perform this
installation.

2. As a module within a NixOS system configuration. This allows the
user profiles to be built together with the system when running
`nixos-rebuild`. See <<sec-flakes-nixos-module>> for a description of
this setup.

3. As a module within a {nix-darwin}[nix-darwin] system configuration.
This allows the user profiles to be built together with the system
when running `darwin-rebuild`. See <<sec-flakes-nix-darwin-module>>
for a description of this setup.

[[sec-flakes-prerequisites]]
=== Prerequisites

* Install Nix 2.4 or later, or have it in `nix-shell`.

* Enable experimental features `nix-command` and `flakes`.
+
** When using NixOS, add the following to your `configuration.nix` and rebuild your system.
+
[source,nix]
nix = {
  package = pkgs.nixFlakes;
  extraOptions = ''
    experimental-features = nix-command flakes
  '';
};
+
** If you are not using NixOS, add the following to `nix.conf` (located at `~/.config/nix/` or `/etc/nix/nix.conf`).
+
[source,bash]
experimental-features = nix-command flakes
+
You may need to restart the Nix daemon with, for example, `sudo systemctl restart nix-daemon.service`.
+
** Alternatively, you can enable flakes on a per-command basis with the following additional flags to `nix` and `home-manager`:
+
[source,console]
----
$ nix --extra-experimental-features "nix-command flakes" <sub-commands>
$ home-manager --extra-experimental-features "nix-command flakes" <sub-commands>
----

* Prepare your Home Manager configuration (`home.nix`).
+
Unlike the channel-based setup,
`home.nix` will be evaluated when the flake is built,
so it must be present before bootstrap of Home Manager from the flake.
See <<sec-usage-configuration>> for introduction about
writing a Home Manager configuration.

[[sec-flakes-standalone]]
=== Standalone setup

1. Set up a flake with a `flake.nix` as follows:
+
[source,nix]
----
{
  description = "Home Manager configuration of Jane Doe";

  inputs = {
    # Specify the source of Home Manager and Nixpkgs.
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { nixpkgs, home-manager, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in {
      homeConfigurations.jdoe = home-manager.lib.homeManagerConfiguration {
        inherit pkgs;

        # Specify your home configuration modules here, for example,
        # the path to your home.nix.
        modules = [
          ./home.nix
        ];

        # Optionally use extraSpecialArgs
        # to pass through arguments to home.nix
      };
    };
}
----
+
[NOTE]
====
* The above example tracks the master branch of Home Manager
and nixos-unstable branch of Nixpkgs.
If you would like to use the `release-22.11` branch,
change the `home-manager` input url to `github:nix-community/home-manager/release-22.11`
and `nixpkgs` url to `github:NixOS/nixpkgs/nixos-22.11`.

* The Home Manager library is exported by the flake under
`lib.hm`.

* You can use the above `flake.nix` as a template in `~/.config/nixpkgs` by
[source,console]
$ nix flake new ~/.config/nixpkgs -t github:nix-community/home-manager
====

2. Install Home Manager and apply the configuration by
+
[source,console]
----
$ nix build --no-link <flake-uri>#homeConfigurations.jdoe.activationPackage
$ "$(nix path-info <flake-uri>#homeConfigurations.jdoe.activationPackage)"/activate
----
+
Substitute `<flake-uri>` with the flake URI of the configuration flake.
If `flake.nix` resides in `~/.config/nixpkgs`,
`<flake-uri>` may be `~/.config/nixpkgs`
as a Git tree or `path:~/.config/nixpkgs` if not.

3. Since the release `21.05`,
building a flake-based configuration is as simple as
+
[source,console]
$ home-manager switch --flake '<flake-uri>#jdoe'
+
once home-manager is installed.
+
Here, `jdoe` is a configuration specified in the flake file,
and `<flake-uri>#jdoe` will be expanded to
`<flake-uri>#homeConfigurations.jdoe.activationPackage`
and be built by Nix.

[NOTE]
====
The flake inputs are not upgraded automatically when switching.
The analogy to the command `home-manager --update ...` is `nix flake update`.

If updating more than one input is undesirable,
the command `nix flake lock --update-input <input-name>` can be used.

You can also pass flake-related options
such as `--recreate-lock-file` or `--update-input [input]`
to `home-manager` when building/switching,
and these options will be forwarded to `nix build`.
See the {nixos-wiki-flakes}[NixOS Wiki page] for detail.
====

[[sec-flakes-nixos-module]]
=== NixOS module

To use Home Manager as a NixOS module,
a bare-minimum `flake.nix` would be as follows:

[source,nix]
----
{
  description = "NixOS configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = inputs@{ nixpkgs, home-manager, ... }: {
    nixosConfigurations = {
      hostname = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix
          home-manager.nixosModules.home-manager
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.jdoe = import ./home.nix;

            # Optionally, use home-manager.extraSpecialArgs to pass
            # arguments to home.nix
          }
        ];
      };
    };
  };
}
----

The Home Manager configuration is then part of the NixOS configuration
and is automatically rebuilt with the system when using the appropriate command
for the system, such as `nixos-rebuild switch --flake <flake-uri>`.

You can use the above `flake.nix` as a template in `/etc/nixos` by

[source,console]
$ nix flake new /etc/nixos -t github:nix-community/home-manager#nixos

[[sec-flakes-nix-darwin-module]]
=== nix-darwin module

The flake-based setup of the Home Manager nix-darwin module
is similar to that of NixOS. The `flake.nix` would be:

[source,nix]
----
{
  description = "Darwin configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    darwin.url = "github:lnl7/nix-darwin";
    darwin.inputs.nixpkgs.follows = "nixpkgs";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = inputs@{ nixpkgs, home-manager, darwin, ... }: {
    darwinConfigurations = {
      hostname = darwin.lib.darwinSystem {
        system = "x86_64-darwin";
        modules = [
          ./configuration.nix
          home-manager.darwinModules.home-manager
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.jdoe = import ./home.nix;

            # Optionally, use home-manager.extraSpecialArgs to pass
            # arguments to home.nix
          }
        ];
      };
    };
  };
}
----

and it is also rebuilt with the nix-darwin generations.
The rebuild command here may be `darwin-rebuild switch --flake <flake-uri>`.

You can use the above `flake.nix` as a template in `~/.config/darwin` by

[source,console]
$ nix flake new ~/.config/darwin -t github:nix-community/home-manager#nix-darwin
