How to use overlays in a Flake with flake-parts?


I like how flake-parts is built around the modules concept, but I have not been able to understand how to apply overlays on nixpkgs, that is I want the pkgs argument of the perSystem function of my flake modules to include the few derivations that I’d like to overlay onto nixpkgs. I am not interested in exposing overlays from my flake, but using one internally.

I have been looking at this for a couple days now and haphazardly tried this in my flake.nix today which didn’t work:

  outputs = { self, flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit self; } {
      imports = [
      systems = [ "x86_64-linux" ]; # "armv6l-linux" "aarch64-darwin"
      perSystem = { config, self', inputs', pkgs, system, ... }: {
        _module.args.pkgs = import inputs'.nixpkgs {
          inherit system;
          overlays = [(final: prev: rec {
            fooDep = prev.callPackage ./third_party/foo.nix;
            barDep = prev.callPackage ./third_party/bar.nix { inherit fooDep };
      flake = {

Maybe @roberth has an idea? :pray:

1 Like

I’m not specifically knowledgeable about flake-parts, but assuming the perSystem option is in fact a submodule, and doesn’t already provide a pkgs argument (say, through specialArgs, which would override the _module.args), this should work fine.

I would be using final.callPackage here (then you wouldn’t need the inherit fooDep)

More generally, let me ask the question: Do you need an overlay for this? Overlays are often used when they truly aren’t needed. Can’t you just pass a mypkgs argument with just fooDep and barDep in it, which are built on top of nixpkgs?

So are you saying this should work?

Oh, thank you for the suggestion about how to remove that rec, it makes sense!

I would like to use an overlay because those dependencies need to be cross-compiled, and so far (with my knowledge) this has meant carrying around two versions of pkgs around (one for the build system, one for the host system), and using both to define my derivations. But with overlays I could just define them “normally”, and then refer to the cross-compiled version via pkgs.pkgsCross which feels a lot more elegant.

With my limited knowledge, it seems likely. I listed the main reasons it might not work that I might not be aware of, so if it isn’t working those are good things to check.

Fair enough.

Keep in mind that inputs'.nixpkgs is not the original flake input but instead something like

  <attr> = nixpkgs.<attr>.${system};
  # ...

which does not contain the .outPath attribute that flake inputs usually contain, which allows the

import nixpkgs {/*...*/}

syntax you’re used to in flakes, hence your import fails. So you can either thread through the toplevel nixpkgs input or use inputs'.nixpkgs.legacyPackages.path as thats an attribute provided by nixpkgs.

For some inspiration you might want to look at my flake-module, which I originally hacked together specifically to allow for cross compiling (via the crossSystems option) and overlays (see the nixpkgs.overlays option), also see the issue linked to at the top of the file.

You can add an overlay to flake-parts by setting _module.args.pkgs. e.g.

        _module.args.pkgs = import self.inputs.nixpkgs {
          inherit system;
          overlays = [self.overlays.default];
          config.allowUnfree = true;

Thank you very much, this seems to be the way to go!

And thanks to @BurNiinTRee, for the context about why my original attempt did not work. I tried to get some inspiration from your flake-module but, to be honest, I couldn’t make sense everything that was going on there.

Do you know how to configure multiple overlays to different hosts?

No, I don’t and I’m not sure what to suggest. The overlay example I shared will modify the pkgs for the entire system.

Personally I avoid overlays as much as possible. I prefer other patterns that don’t rely on them.

1 Like

Depending on the meaning if “per host” the solution is different, and there are basically three answers to the questions:

  1. You use NixOS and are talking about the overlay that is used in each system configuration, then set the nixpkgs.overlays option in that system configuration.
  2. You use home-manager standalone, and think in hosts rather than user environments, basically the same applies as in 1.
    1. When using HM as a system module and useGlobalPkgs is activated, same as 1. applies
    2. When using HM as a system module and useGlobalPkgs is not activated, as as 2. applies
  3. You want to have different overlays depending on the evaluation host. This is generally not possible.

Thanks, this helped me. More about this Overlays - flake-parts