Help moving system configuration + home manager to a flake

Hey! :wave:

I’ve got some questions on moving a NixOS system configuration to a flake. I’m currently not able to make it work and I have some question about it in general.

Edit: I may have been able to solve the first issue by using a higher home.stateVersion (don’t think I had one before(?) and used the system.stateVersion). This seems to get past the first issue, but I’m now stuck at using overlays again :see_no_evil:

Having seen this video on moving your NixOS system configuration to a flake (which made it look real easy), I thought I’d give it a go myself. But in doing so, I encountered a few issues. I’ve managed to solve (I think?) some of them, but am now stuck. I was hoping I could get some help.

For reference, here’s the current state of the flake I’m using (tracking my efforts, so it may change).

For reference, here's the current state of the flake I'm using.
  description = "My Nixos system config";

  inputs =
    # let
    #   systemVersion = "22.05";
    #   # if system version is "unstable" use "master"; otherwise use "release-${systemVersion}"
    #   # homeManagerVersion = if systemVersion == "unstable" then "master" else "release-${systemVersion}";
    # in
      # nixpkgs.url = "nixpkgs/nixos-${systemVersion}";
      nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
      home-manager.url = "github:nix-community/home-manager/master";
      home-manager.inputs.nixpkgs.follows = "nixpkgs";
      musnix.url = "github:musnix/musnix";
      emacsOverlay.url = "github:nix-community/emacs-overlay";

  outputs = { nixpkgs, home-manager, musnix, emacsOverlay, ... }@inputs:
      system = "x86_64-linux";

      pkgs = import nixpkgs {
        inherit system;
        config = {
          allowUnfree = true;

      lib = nixpkgs.lib;

      homeManagerConfigs = {
        phaaze = home-manager.lib.homeManagerConfiguration {
          pkgs = nixpkgs.legacyPackages.${system};
          # pkgs = import nixpkgs {
          #   overlays = [emacsOverlay.overlay];
          #   inherit system;
          # };

          modules = [
              nixpkgs.overlays = [ emacsOverlay.overlay ];
            # ({ pkgs, ... }: {
            #   nixpkgs.overlays = [ emacsOverlay.overlay ];
            # })
              home = {
                username = "thomas";
                homeDirectory = "/home/thomas";
                stateVersion = "18.09";

      nixosConfigurations = {
        phaaze = lib.nixosSystem {
          inherit system;

          modules = [

The current issue is that when I try to build the home manager package (using nix build .#homeManagerConfigs.phaaze.activationPackage), I get this message:

error: cannot look up '<nixpkgs>' in pure evaluation mode (use '--impure' to override)

       at /nix/store/bdk5advb7w9kfnv25z9j6xmmmqfy9sga-source/modules/modules.nix:301:11:

          300|         else
          301|           <nixpkgs>);
             |           ^
          302|       _module.args.pkgs = lib.mkDefault pkgs;
(use '--show-trace' to show detailed location information)

For most of the error messages I have found, I have been able to go and change the source file to adapt to the error message, but this doesn’t seem to be (directly) in my files at all. Following the file it points to, I do indeed find the line in question, but it looks auto-generated to me, and I don’t know how or if I can change it:

`modules.nix`, the file that errors
{ pkgs

# Note, this should be "the standard library" + HM extensions.
, lib

# Whether to enable module type checking.
, check ? true

  # If disabled, the pkgs attribute passed to this function is used instead.
, useNixpkgsModule ? true }:

with lib;


  modules = [
    (pkgs.path + "/nixos/modules/misc/assertions.nix")
    (pkgs.path + "/nixos/modules/misc/meta.nix")
  ] ++ optional useNixpkgsModule ./misc/nixpkgs.nix
    ++ optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix;

  pkgsModule = { config, ... }: {
    config = {
      _module.args.baseModules = modules;
      _module.args.pkgsPath = lib.mkDefault
        (if versionAtLeast config.home.stateVersion "20.09" then
      _module.args.pkgs = lib.mkDefault pkgs;
      _module.check = check;
      lib =;
    } // optionalAttrs useNixpkgsModule {
      nixpkgs.system = mkDefault pkgs.stdenv.hostPlatform.system;

in modules ++ [ pkgsModule ]

Does anyone know what this is about or what might be going on?

Extra questions

I have a few more questions relating to using flakes for system configuration. Some of them may or may not relate to the issue: I genuinely don’t know.

Nix expressions outside of outputs

From my understanding, you can’t do any sort of evaluation outside of the outputs attribute, is that correct? I wanted to put my system version into a variable and use that to update all paths in the inputs attribute, but using a let block, I was told that it got a thunk but expected a set. I think I found a github thread about this when searching, but it was definitely surprising. Is there any way about this? I’d like to set system version once and then populate the nixos and home-manager channels with the correct url based on that.

How do you use overlays?

(This may relate to the issue I’m having, but I don’t know.)

Up until now, I’ve used the Nix community emacs overlay to get my emacs version. I’ve imported it as an overlay with fetchTarball in my home-manager config. However, I thought I’d try and add the overlay to the flake instead (seems like the right thing to do), but I can’t find any good documentation on how to add overlays in flakes. I did manage to find this response in a thread here on discourse which gives a brief explanation on how to set it up. That seems to work, but it doesn’t say anything about how you reference the overlay in any of the other modules.

What I ended up doing was this:

        phaaze = home-manager.lib.homeManagerConfiguration {
          pkgs = nixpkgs.legacyPackages.${system};

          modules = [
              nixpkgs.overlays = [ emacsOverlay.overlay ];
              home = {
                username = "thomas";
                homeDirectory = "/home/thomas";
                stateVersion = "18.09";

and then referencing the version of emacs in my home manager module params:

{ pkgs, config, emacsNativeComp, ... }: # adding emacsNativeComp to the top of the file

  # ... rest of the config

Is that how it’s supposed to be done? Or is there another way?

Update: The overlay method does not work

After updating the home.stateVersion I used, I got past the initial hurdle mentioned above. It now gets to the point where it seems to try and evaluate my home config, but it can’t find emacsNativeComp. So the overlay question is now the main one: how do you use them and reference them in pre-existing modules?

Thanks a lot for making it all the way down here! Any input (on any of the questions) would be very much appreciated :pray: If you need additional info, I would of course be happy to provide that too :grinning_face_with_smiling_eyes:

1 Like

This needs to be at least 20.09, everything older than that can not be used for HM flake configuration.

Thanks! :grinning_face_with_smiling_eyes: Yeah, I found that out (edited my post after). Don’t think I’ve ever set a version for home manager before, so I thought it should be the same as the system state version. Setting it to 22.11 got me past that hurdle, but also revealed that my overlay didn’t work after all. Would you know how to use overlays with flakes and home manager?

You add them to nixpkgs.overlays, this works for me just fine when building Emacs.

Cool. How do you do that? As mentioned in the post, I tried the following:

        phaaze = home-manager.lib.homeManagerConfiguration {
          pkgs = nixpkgs.legacyPackages.${system};

          modules = [
              nixpkgs.overlays = [ emacsOverlay.overlay ];
              home = {
                username = "thomas";
                homeDirectory = "/home/thomas";
                stateVersion = "22.11";

but I don’t know how to reference the overlay in the home manager module.

To be clear, I’m still using more or less the same home-manager config file as I was before flakes. Previously I’d created an unstable channel by fetching a tarball and adding an overlay. That way I could reference the emacs version as unstable.emacsNativeComp. Now, however, I don’t know how to reference the package in the home manager config file. Could you shed some light on that?

Hmm, oh, right. It just becomes part of the pkgs argument in that case. Yeah, that does seem to work, actually :partying_face:

How many times do I need to set allowUnfree? Can I set it once and have it apply for everything?

Once per import.

nixpkgs.config.allowUnfree should be applied to the passed in pkgs, though there is a known bug in HM/nixpkgs that makes it not work, as a workaround you can use nixpkgs.config.allowUnfreePredicate = _: true.

If you import another instance, you need to apply the configuration again.

Thanks! Yeah, I found mention of that workaround and that does seem to work.

Once per import.

I’m sorry, but I’m not sure I understand what that means. What is an import and how do you set it? I set this in a let block leading into outputs, but I don’t think I ever use the variable anywhere:

      pkgs = import nixpkgs {
        inherit system;
        config = {
          allowUnfree = true;

Does it get used for anything at all, then? And do you know what the

          pkgs = nixpkgs.legacyPackages.${system};

part of the home manager config is? Could I use that somehow?