A man may well bring a horse to the water, but he cannot make him drink with he will. -- John Heywood

Flakes in NixOS

Flakes are tools used to automate development environments. Each flake contains input, output and follow syntax, which is very common in NixOS environments.

The widely used data type in Nix is an attribute set: a data type for storing key-value pairs. It is similar to a JSON object or a hashmap in many languages. Its syntax is confusingly similar to a list of statements in C-like languages:

{
  hello = "world";
  foo = "bar";
}

The set above is equivalent to this JSON object:

{
    "hello": "world",
    "foo": "bar"
}
[superuser@valhalla:/my-flake]$ nix develop
[superuser@valhalla:/my-flake]$ hello

Hello, world!

We have now created a simple flake. These "flakes" can help to automate build environments.

A step further - Create flake that does something

[superuser@valhalla:]$ mkdir basic-flake
[superuser@valhalla:]$ cd basic-flake/

[superuser@valhalla:/basic-flake]$ cat > flake.nix

{
  outputs = { self }: { };
}

[superuser@valhalla:/basic-flake]$ nix eval .#foo

We don't have too much use of this flake. Let's extend it with some functionality.

Using inputs and outputs in flakes

[superuser@valhalla:/basic-flake]$ cat flake.nix

{
  outputs = { self }: { foo = "bar"; };
}

$ nix eval .#foo

warning: Git tree '/home/superuser/basic-flake' is dirty

"bar"

Flake which uses nixpkgs as input

Your flakes can use packages as outputs. In this case they will be pulled the first time you use the flake. The idea is to provide you with functions and capabilities.

[superuser@valhalla:/basic-flake]$ cat flake.nix

{
  inputs = { nixpkgs.url = "github:nixos/nixpkgs"; };
  outputs = { self, nixpkgs }: { foo = "bar"; };
}

$ nix eval .#foo

warning: Git tree '/home/galt/da/basic-flake' is dirty

"bar"

[superuser@valhalla:/basic-flake]$ nix build .#hello

warning: Git tree '/home/galt/da/basic-flake' is dirty

evaluating derivation 'git+file:///home/galt/da/basic-flake#hello'

querying hello-2.12.2 on https://cache.nixos.org
[0/1 built, 1/0/1 copied (0.0/0.3 MiB), 0.0/0.1 MiB DL] fetching hello-2.12.2 from https://cache.nixos.org


[superuser@valhalla:/basic-flake]$ hello

Hello, world!

Extend development environment with other packages

Our development environment can contain any package in any version supported by Nix. In this example we will pull cowsay and pingus.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
    wasmProposals = {
      url = "github:WebAssembly/proposals";
      flake = false;
    };
  };
  outputs = { self, nixpkgs, wasmProposals } :{
    packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
    devShell.x86_64-linux =
      nixpkgs.legacyPackages.x86_64-linux.mkShell {
        buildInputs = [
          self.packages.x86_64-linux.hello
          nixpkgs.legacyPackages.x86_64-linux.cowsay
          nixpkgs.legacyPackages.x86_64-linux.pingus
        ]; };
    };
}

[superuser@valhalla:/basic-flake]$

Entering development environment with flakes

In order to "enter" the development environment with flakes, execute:

$ nix develop -c $shell

warning: Git tree '/home/superuser/da/basic-flake' is dirty
evaluating derivation 'git+file:///home/galt/da/basic-flake#devShells.x86_64-linux.default'
evaluating derivation 'github:nixos/nixpkgs/02fb5aea5577e0c957abb8759a75deb37106cea9?narHash=sha256-TKbKISE2crHAukW
... lots of other messages, downloading packages ...

From there, we can test that our packages were installed correctly:

\[\][\[\]superuser@valhalla:/basic-flake]$\[\] fortune 2>&1 | cowsay
 ____________________________
< fortune: command not found >
 ----------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

\[\][\[\]superuser@valhalla:/basic-flake]$\[\] pingus

The game starts and runs normally

\[\][\[\]superuser@valhalla:/basic-flake]$\[\] exit

But what we currently have is issues with is automatically pulling git repos from our flakes. If you know how to do it, please let me know. I am welw #dflund. The best I have is something like this, and it does not work:

[superuser@valhalla:/basic-flake]$ cat flake.nix
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
    wasmProposals = {
      url = "github:WebAssembly/proposals";
      flake = false;
    };
    # wasm-repo = {
    #  type = "github";
    #  owner = "WebAssembly";
    #  repo = "proposals";
    #  ref = "main";
    #};
  };
  outputs = { self, nixpkgs, wasmProposals } :{
    packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
    devShell.x86_64-linux =
      nixpkgs.legacyPackages.x86_64-linux.mkShell {
        buildInputs = [
          self.packages.x86_64-linux.hello
          nixpkgs.legacyPackages.x86_64-linux.cowsay
          nixpkgs.legacyPackages.x86_64-linux.pingus
        ]; };
    };
}

Summary

Our flake looks as following:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
    wasm-repo = {
      type = "github";
      owner = "WebAssembly";
      repo = "proposals";
      ref = "main";
    };
  };
  outputs = { self, nixpkgs } :{
    packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
    devShell.x86_64-linux =
      nixpkgs.legacyPackages.x86_64-linux.mkShell {
        buildInputs = [
          self.packages.x86_64-linux.hello
          nixpkgs.legacyPackages.x86_64-linux.cowsay
          nixpkgs.legacyPackages.x86_64-linux.pingus
        ]; };
    };
}

What we've done is:

Extended the development environment: