# Nix flakes

<Admonition warning open title="Flakes are experimental in upstream Nix but stable in Determinate Nix" id="flakes-status">
In the [upstream Nix project][upstream], flakes are **still considered an experimental feature**, and there is currently no concrete timeline for declaring them stable.
Because of this, if you use upstream Nix you can only use flakes if you explicitly [enable them][enable-flakes].

In [Determinate Nix][det-nix], the downstream distribution of Nix from [Determinate Systems][detsys] that you install at the beginning of the [quick start][quick-start], flakes are [**considered stable**][stable-flakes], enabling you to use them out of the box.

Whether you opt for upstream Nix or Determinate Nix, we strongly recommend that you either learn to use flakes if you're already a Nix user or begin your Nix journey with flakes if you're just [getting started][quick-start].
</Admonition>

A Nix _flake_ is a directory with a `flake.nix` and [`flake.lock`](#lockfile) at the root that [outputs](#outputs) Nix expressions that others can use to do things like [build packages][packages], [run programs][run], use [development environments][env], or stand up [NixOS] systems.
If necessary, flakes can use the outputs of other flakes as [inputs](#inputs).

<Admonition success title="Mental model" id="flakes-mental-model" open>
It may be helpful to think of flakes as processors of [Nix code][lang].
They take Nix expressions as [input](#inputs) and [output](#outputs) things that Nix can use, like [package definitions][packages], [development environments][env], or [NixOS] configurations.

Flakes thus form a kind of chain.
Let's say that I create a flake that uses a helper function output by [Nixpkgs]&mdash;which is a flake!&mdash;to define a package build.
My teammate could then use the package definition from my flake as part of a Nix development environment.
Another team then could use that development environment in one of their projects.
And so on.

</Admonition>

## Flake references \{#references}

A _flake reference_ is a string representation of where the flake is located.
Flake references are used in two places:

1. In flake [input declarations](#inputs) to depend on outputs from the flake.
1. In shell environments when running commands like `nix run github:DeterminateSystems/flake-checker` (which runs the [flake-checker] program).

Here are some example flake references:

Reference | Description
:---------|:-----------
`path:/home/nix-stuff/my-flake` | The `/home/nix-stuff/my-flake` directory on the current host
`github:DeterminateSystems/zero-to-nix` | The [DeterminateSystems/zero-to-nix][gh-z2n] GitHub repository
`github:DeterminateSystems/zero-to-nix/other` | The [`other`][other] branch of the [DeterminateSystems/zero-to-nix][gh-z2n] GitHub repository
`github:DeterminateSystems/zero-to-nix/d51c83a5d206e882a6f15a282e32b7079f5b6d76` | Commit [`d51c83a5d206e882a6f15a282e32b7079f5b6d76`][hash] on the [DeterminateSystems/zero-to-nix][gh-z2n] GitHub repository
`github:DeterminateSystems/zero-to-nix/pull/2/head` | Pull request 1 on the [DeterminateSystems/zero-to-nix][gh-z2n] GitHub repository
`nixpkgs` | The most recent revision of the [`nixpkgs-unstable`][unstable] branch of [Nixpkgs] (an alias for `github:NixOS/nixpkgs`)
`nixpkgs/release-22.11` | The [`release-22.11`][22-11] branch of Nixpkgs
[`https://flakehub.com/f/NixOS/nixpkgs/0.2405.*`][fh-nixpkgs] | The most recent revision of the [`nixos-24.05`][branch] branch of [Nixpkgs] hosted on [FlakeHub]

You can find a more systematic treatment of flake references in the [official documentation][refs-official].

### References and revisions \{#revisions}

Flake references are _always_ to a specific revision of the flake.
[Nixpkgs], for example, is a flake but each revision of Nixpkgs&mdash;and there are many thousands&mdash;has a flake reference.

## Flake inputs \{#inputs}

_Flake inputs_ are Nix dependencies that a flake needs to be built.
Each input in the set can be pulled from various sources, such as github, generic git repositories, and even your filesystem.

Furthermore, inputs can modify each other's inputs to make sure that,
for example, multiple dependencies all rely on the same version of nixpkgs.
This is done via the `inputs.<input>.follows` attribute.

```nix title="flake.nix"
{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs";
}
```

You can find a full breakdown of the flake input schema in the [Nix manual][manual].

### The `flake.lock` file \{#lockfile}

All flake inputs are [pinned][pinning] to specific [revisions](#revisions) in a lockfile called `flake.lock`.
This file stores revision information as [JSON].

The `flake.lock` file ensures that Nix flakes have purely deterministic outputs.
A `flake.nix` file without an accompanying `flake.lock` should be considered incomplete and a kind of proto-flake.
Any Nix CLI command that is run against the flake&mdash;like `nix build`, `nix develop`, or even `nix flake show`&mdash;generates a `flake.lock` for you.

Here's an example section of a `flake.lock` file that pins [Nixpkgs] to a specific revision:

```json title="flake.lock"
{
  "nodes": {
    "nixpkgs": {
      "locked": {
        "lastModified": 1668703332,
        // A SHA of the contents of the flake
        "narHash": "sha256-PW3vz3ODXaInogvp2IQyDG9lnwmGlf07A6OEeA1Q7sM=",
        // The GitHub org
        "owner": "NixOS",
        // The GitHub repo
        "repo": "nixpkgs",
        // The specific revision
        "rev": "de60d387a0e5737375ee61848872b1c8353f945e",
        // The type of input
        "type": "github"
      }
    }
    // Other inputs
  }
}
```

If this `flake.lock` were alongside a `flake.nix` with this [input block](#inputs)...

```nix title="flake.nix"
{
  inputs.nixpkgs.url = "nixpkgs";

  outputs = { self, nixpkgs }: {
    # Define outputs here
  };
}
```

...the `nixpkgs` attribute would be implicitly pinned to the `de60d387a0e5737375ee61848872b1c8353f945e` revision&mdash;even though that revision information isn't in Nix code itself.

### Flake registries \{#registries}

[_Flake registries_][registry-official] are a convenience feature that enables you to refer to flakes using symbolic identifiers rather than full flake references.
The most widely used symbolic identifier is `nixpkgs`, which is an alias for the `github:NixOS/nixpkgs/nixpkgs-unstable` flake [reference](#references)

Some symbolic identifiers that you may encounter:

| Symbolic identifier          | Full flake reference                    |
| :--------------------------- | :-------------------------------------- |
| [`nixpkgs`][nixpkgs]         | `github:NixOS/nixpkgs/nixpkgs-unstable` |
| [`flake-utils`][flake-utils] | `github:numtide/flake-utils`            |
| [`home-manager`][hm]         | `github:nix-community/home-manager`     |

The full default global flake registry is kept as a [JSON file][registry-json].

Here's an example flake that uses symbolic identifiers:

```nix title="flake.nix"
{
  outputs = { self, nixpkgs, flake-utils }:
    let
      pkgs = import nixpkgs { inherit system; };
    in flake-utils.lib.eachDefaultSystem (system: {
      devShells.default = pkgs.mkShell {
        packages = with pkgs; [ curl git jq wget ];
      };
    });
}
```

Note that the [`inputs` block](#inputs) has been omitted in this flake.
Using flake registries is always optional.

## Flake outputs \{#outputs}

_Flake outputs_ are what a flake produces as part of its build.
Each flake can have many different outputs simultaneously, including but not limited to:

- [Nix packages][packages]
- [Nix development environments][env]
- [NixOS] configurations
- [Nix templates](#templates)

Flake outputs are defined by a function, which takes an attribute set as input, containing each of the inputs to that flake (named after the chosen identifier in the [inputs](#inputs) section).

### Exporting functions \{#functions}

In addition to things like packages and NixOS configurations, flakes can also output Nix [functions] for use elsewhere.
[Nixpkgs], for example, outputs many helper functions via the `lib` attribute.

<Admonition info title="The `lib` convention">
  The convention of using `lib` to output functions is observed not just by
  Nixpkgs but by many other Nix projects. You're free, however, to output
  functions via whichever attribute you prefer.
</Admonition>

Here's an example flake that outputs a `sayHello` function, via the `lib` attribute, that takes a name as an input and outputs a string saying hello to a person with that name:

```nix title="flake.nix"
{
  outputs = { self }: {
    lib = {
      sayHello = name: "Hello there, ${name}!";
    };
  };
}
```

Another Nix flake could then specify this flake as an [input](#inputs) and use `sayHello` for whatever purpose.

### System specificity

Some flake outputs need to be [system specific][specificity], including [packages], [development environments][env], and [NixOS] configurations.
Here's an example flake that outputs a package that can be used by `x86_64-linux` systems (64-bit AMD/Intel Linux):

```nix title="flake.nix"
{
  outputs = { self, nixpkgs }: let
    # Declare the system
    system = "x86_64-linux";
    # Use a system-specific version of Nixpkgs
    pkgs = import nixpkgs { inherit system; };
  in {
    # Output `ponysay` as the default package of the flake
    packages.${system}.default = pkgs.ponysay;
  };
}
```

In many cases, however, you'll need to output things like [packages] or [development environments][env] for multiple systems.
Helper libraries like [`flake-utils`][flake-utils] provide convenient mechanisms for doing that.
You can also use Nix functions like this:

```nix title="flake.nix"
{
  outputs = { self, nixpkgs }: let
    # The set of systems to provide outputs for
    allSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];

    # A function that provides a system-specific Nixpkgs for the desired systems
    forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f {
      pkgs = import nixpkgs { inherit system; };
    });
  in {
    packages = forAllSystems ({ pkgs }: {
      default = {
        # Package definition
      };
    });
  };
}
```

## Flake templates \{#templates}

[_Flake templates_][init] enable you to either initialize a new Nix project with pre-supplied content or add a set of files to an existing project.
You can initialize a flake template using the [`nix flake init`][init] command.
Flakes can [output](#outputs) templates using the `templates` attribute.
Here's an example:

```nix title="flake.nix"
{
  outputs = { self }: {
    templates = {
      starter-template = {
        path = ./my-starter-template;
        description = "A getting started template for a new Nix project";
      };
    };
  };
}
```

If you ran `nix flake init --template <reference>` against this template definition, Nix would copy the contents of the `./my-starter-template` directory into the current directory (without overwriting existing files).

[22-11]: https://github.com/nixOS/nixpkgs/tree/release-22.11
[branch]: https://github.com/nixos/nixpkgs/tree/nixos-24.05
[det-nix]: https://docs.determinate.systems/determinate-nix
[detsys]: https://determinate.systems
[enable-flakes]: https://wiki.nixos.org/wiki/Flakes#Setup
[env]: /concepts/dev-env
[fh-nixpkgs]: https://flakehub.com/flake/NixOS/nixpkgs
[flake-checker]: https://github.com/DeterminateSystems/flake-checker
[flake-utils]: https://github.com/numtide/flake-utils
[flakehub]: https://flakehub.com
[functions]: /concepts/nix-language
[gh-z2n]: https://github.com/DeterminateSystems/zero-to-nix
[hash]: https://github.com/DeterminateSystems/zero-to-nix/tree/d51c83a5d206e882a6f15a282e32b7079f5b6d76
[hm]: https://github.com/nix-community/home-manager
[init]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake-init
[json]: https://json.org
[lang]: /concepts/nix-language
[manual]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-inputs
[nixos]: /concepts/nixos
[nixpkgs]: /concepts/nixpkgs
[other]: https://github.com/DeterminateSystems/zero-to-nix/tree/other
[packages]: /concepts/packages
[pinning]: /concepts/pinning
[refs-official]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-references
[registry-json]: https://github.com/NixOS/flake-registry/blob/master/flake-registry.json
[registry-official]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-registry
[quick-start]: /start
[run]: /start/nix-run
[specificity]: /concepts/system-specificity
[stable-flakes]: https://determinate.systems/blog/determinate-nix-30
[unstable]: https://github.com/NixOS/nixpkgs/tree/nixpkgs-unstable
[upstream]: https://github.com/NixOS/nix