Error when using `flake-utils.lib.eachDefaultSystem`

I have below a simple flake that gives me a dev shell with Python:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
  };

  outputs =
    {
      self,
      nixpkgs,
    }:

    let
      system = "aarch64-darwin";
      pkgs = import nixpkgs { inherit system; };
    in
    {
      devShells.${system}.default = pkgs.mkShell {
        buildInputs = with pkgs; [
          python314
        ];
      };
    };
}

and when I run `nix flake show`, I get this (successful) output:

% nix flake show
git+file://<PATH TO FLAKE>
└───devShells
    └───aarch64-darwin
        └───default: development environment 'nix-shell'

Now I want to make this more cross-platform, so I use flake-utils.lib.eachDefaultSystem:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs { inherit system; };
      in
      {
        devShells.${system}.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            python314
          ];
        };
      }
    );
}

But now when I run `nix flake show` I get this error/output:

% nix flake show
git+file://<PATH TO FLAKE>
└───devShells
    ├───aarch64-darwin
error: expected a derivation

Why am I getting this error? how do I fix it?

  1. Why you don't need flake-utils
  2. You have devShells.aarch64-linux.aarch64-linux.default et all.
  3. your issue is mentioned as an example of things going wrong in 1

great read! so using `flake-parts`, this is the more widely accepted way to do it?:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    flake-parts.url = "github:hercules-ci/flake-parts";
  };

  outputs =
    inputs@{
      self,
      nixpkgs,
      flake-parts,
    }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      perSystem =
        {
          config,
          self',
          inputs',
          pkgs,
          system,
          ...
        }:
        {
          devShells.default = pkgs.mkShell {
            buildInputs = with pkgs; [
              python314
            ];
          };
        };

      systems = [
        "x86_64-linux"
        "aarch64-linux"
        "aarch64-darwin"
        "x86_64-darwin"
      ];
    };
}

Even the flake-parts is generally overdoing it, the genAttrs suffices.

2 Likes

What waffles says, or simple and easy, just hardcode the one system you actually use and are able to verify.

1 Like

this makes sense as a practical rule of thumb, but also I’m still learning the nix language and want to know how to do the harder more scalable thing, even if it’s not necessarily the best choice for my current goals.

so like this?:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
  };

  outputs =
    {
      self,
      nixpkgs,
    }:

    let
      forEachSystem =
        makeFlakeWithSystem:
        nixpkgs.lib.genAttrs [
          "aarch64-darwin"
          "aarch64-linux"
          "x86_64-darwin"
          "x86_64-linux"
        ] makeFlakeWithSystem;
    in
    {
      devShells = forEachSystem (
        system:
        let
          pkgs = import nixpkgs { inherit system; };
        in
        {

          default = pkgs.mkShell {
            buildInputs = with pkgs; [
              python314
            ];
          };
        }
      );
    };
}