Autowiring

An optional autowiring module is provided that will scan the directory structure and wire up the appropriate flake outputs automatically without you having to do it manually.

A ready demonstration is available in nixos-unified-template as well as srid/nixos-config. In the latter, you will notice the following directory structure:

โฎ lsd --tree --depth 1 configurations modules overlays packages
๐Ÿ“ configurations
โ”œโ”€โ”€ ๐Ÿ“ darwin
โ”œโ”€โ”€ ๐Ÿ“ home
โ””โ”€โ”€ ๐Ÿ“ nixos
๐Ÿ“ modules
โ”œโ”€โ”€ ๐Ÿ“ darwin
โ”œโ”€โ”€ ๐Ÿ“ flake
โ”œโ”€โ”€ ๐Ÿ“ home
โ””โ”€โ”€ ๐Ÿ“ nixos
๐Ÿ“ overlays
โ””โ”€โ”€ โ„๏ธ default.nix
๐Ÿ“ packages
โ”œโ”€โ”€ โ„๏ธ git-squash.nix
โ”œโ”€โ”€ โ„๏ธ sshuttle-via.nix
โ””โ”€โ”€ ๐Ÿ“ twitter-convert

Each of these are wired to the corresponding flake output, as indicated in the below table:

DirectoryFlake Output
configurations/nixos/foo.nix 1 nixosConfigurations.foo
configurations/darwin/foo.nix 1 darwinConfigurations.foo
configurations/home/foo.nix 1 legacyPackages.${system}.homeConfigurations.foo 2
modules/nixos/foo.nixnixosModules.foo
modules/darwin/foo.nixdarwinModules.foo
modules/flake/foo.nixflakeModules.foo
overlays/foo.nixoverlays.foo
packages/foo.nixpackages.${system}.foo 3

flake-parts

Autowiring is also provided if you use just flake-parts, via the lib.mkFlake function. In your top-level flake.nix, you only need to define your outputs as follows:

{
  inputs = ...;
  outputs = inputs:
    inputs.nixos-unified.lib.mkFlake
      { inherit inputs; root = ./.; };
}

This will,

  • Auto-import flake-parts modules under either ./nix/modules/flake or ./modules/flake (whichever exists)
  • Use a sensible default for systems which can be overriden.
  • Pass root as top-level module args, as a non-recursive way of referring to the path of the flake (without needing inputs.self).

See srid/haskell-templateโ€™s flake.nix for a ready example. For another example, see this emanote PR.

Package Autowiring Example

The packages/ directory allows you to define custom packages that will be automatically wired as flake outputs. Hereโ€™s an example project structure:

โฎ lsd --tree --depth 2 packages
๐Ÿ“ packages
โ”œโ”€โ”€ โ„๏ธ hello-world.nix
โ””โ”€โ”€ ๐Ÿ“ complex-app
    โ””โ”€โ”€ โ„๏ธ default.nix

Each package file should export a function compatible with pkgs.callPackage. Here are two examples:

packages/hello-world.nix - Simple shell script package:

{ lib, writeShellApplication }:

writeShellApplication {
  name = "hello-world";
  text = ''
    echo "Hello from my autowired package!"
    echo "Args: $*"
  '';
  meta = {
    description = "A simple hello world script";
    license = lib.licenses.mit;
  };
}

packages/complex-app/default.nix - Directory-based package:

{ lib, stdenv, makeWrapper }:

stdenv.mkDerivation {
  pname = "complex-app";
  version = "1.0.0";

  src = ./.;

  nativeBuildInputs = [ makeWrapper ];

  installPhase = ''
    mkdir -p $out/bin
    cp app.sh $out/bin/complex-app
    chmod +x $out/bin/complex-app
  '';

  meta = {
    description = "A more complex application";
    license = lib.licenses.gpl3;
    platforms = lib.platforms.unix;
  };
}

After defining these packages, they become available in your flake outputs:

# Build and run packages
nix build .#hello-world
nix run .#complex-app

# List all autowired packages
nix flake show | grep packages

The packages will appear as:

  • packages.${system}.hello-world
  • packages.${system}.complex-app
Footnotes
1.
This path could as well be configurations/nixos/foo/default.nix. Likewise for other output types.
2.
Why legacyPackages? Because, creating a home-manager configuration requires pkgs. See https://github.com/nix-community/home-manager/issues/3075
3.
Package files should export a function that can be called with callPackage. The autowiring system automatically calls pkgs.callPackage on each package file, making them available as packages.${system}.{name} in your flake outputs.
Links to this page