Conditionally Import Configurations with Home-Manager

I’m creating a beginner-friendly configuration and I want it to be as easy to set up as possible.

It would be nice to have specific categories, like development, games, browsers, etc. that I could
enable/disable making it a lot easier to configure. An example code that I’ve tried was this, however infinite recursion errors happened:

  • (Do note that this is pseudocode)
# Filename: modules/home/home.nix
imports = [./development];
options.enableCategories = lib.mkOption {
    type = lib.types.attrsOf lib.types.bool;
    default = {
      communication = false;
      development   = false;
      other         = false;
    };
    description = "App groups for mass enabling and disabling";
  };
# Filename: modules/home/development/default.nix
lib.mkIf config.enableCategories.development {
  imports = [...];
}

However, I’d like another disabledPackages variable for specific programs/packages to be disabled when a group is enabled.

disabledPackages = with pkgs; [neovim];
 # Filters all disabled packages from all packages
lib.filter (pkg: !(lib.elem pkg config.disabledPackages)) allPackages;

Some other ideas I had about this was using homeManagerModules like in the nix-starter-config repo, but I don’t think I could import variables for user-specific stuff (like git username), and package groups would be difficult even without the aforementioned disabled packages feature

My current way of groups is just importing the groups directly, and for disabling packages it’ll be another parameter passed to the module which will then disable the packages.

imports = [
  (import ../../modules/home/communication)
  (import ../../modules/home/development { inherit user nickname email lib; })
];

Before I implement any of these conditional imports, I’d like to hear your thoughts. Am I missing a super simple feature that would fix all of this? Am I on the right track? Am I overthinking it? I’ll provide more info as needed.

Repo:

I have given up on the previous strategy of mass disabling/enabling of packages.
The original point was, if there are tens or hundreds of programs, it would be so much easier to write:

enableCategories.development.enable = true;

Rather than:

imports = [
  import ../../../modules/home/development/git
  import ../../../modules/home/development/neovim
  import ../../../modules/home/development/vscode
  # ... Hundreds more here
];

I’ve realized it’s just easier to make a default.nix file located in .../development/default.nix and import all of the programs, and then import the default.nix into your configuration.nix

  • I don’t know if this exactly works because I don’t use this exact system
# .../development/default.nix
{pkgs, ...}:{
  imports = [
    import ./neovim
    import ./git
    import ./vscode
  ];
}
# .../configuration.nix
{pkgs, ...}:
{
  imports = [
    import ../../modules/home/development/default.nix
  ];
}

If you wanted to answer the original question, that is it. That is the end of my post.

However, I said I don’t exactly use this system in my code, so what do I use? Well, since I don’t have 1000 packages to categorize, I just import them into my flake.nix, which then I import into wherever it’s needed.

# .../development/default.nix

# I just set the paths for all the variables, I do not import them
{
  neovim = ./neovim;
  git = ./git;
  godot4-mono = ./godot4-mono;
}
# ../home/default.nix

# Now I *DO* import all of the paths, as importing them basically 
# just adds the code from the file into this one
{
  art = import ./art;
  development = import ./development;
  games = import ./games;
  communication = import ./communication;
  sound = import ./sound;
  other = import ./other;
}
# flake.nix

# I import the home directory which has all the paths to the programs
homeModules = import ./modules/home; # Modules for users
# .../configuration.nix

# We now import whatever was inside the file 
# (As outputs.homeModules.development.git is just a path, as in when we compile, 
# it transforms into the literal path (root)/modules/home/development/git/default.nix)
imports = [
  # If you were to look at compile time, this is what it would look like:
  # import (root)/modules/home/development/git/default.nix { inherit blah blah; }
  (import outputs.homeModules.development.git { inherit user nickname email lib; })
  outputs.homeModules.other.firefox
];

Ight good luck I’m done for today.

You should know that using import in the module system is fighting the module system. Don’t do it! Use imports (only) instead.

Further discussion here: Import but don’t import your NixOS modules - #4 by waffle8946

FWIW I stick all my modules in a modules/ directory and automatically add everything in it to imports.