Trimming unneeded packages from default NixOS modules

Most modules in NixOS come with a bunch of packages pre-included. For instance, take sway:

extraPackages = lib.mkOption {
      type = with lib.types; listOf package;
      # Packages used in default config
      default = with pkgs; [
        brightnessctl
        foot
        grim
        pulseaudio
        swayidle
        swaylock
        wmenu
      ];
...
}

So essentially, when enabled it will pull all those packages (which I don’t necessarily need): for instance, foot is not my terminal of choice.

  • Q1: Is there a way to apply an overlay to the module, telling it not to install those packages?
  • Q2: Is there a way, given a path in /nix/store, to derive the Nix expression which installed it in the first place?
1 Like

No, overlays only apply to packages (rather, attributes) within a nixpkgs instance. You can patch the nixpkgs instance or disable the module entirely, but in this case I’d just say to set it to an empty list.

programs.sway.extraPackages = [ ];

Kind of. If it’s part of your config, you have to know the option that controls its installation, then you can use nixos-option to find which modules set it. In this case it’s environment.systemPackages.

I personally find trying to use nixos-option environment.systemPackages to be a mess though, because it doesn’t tell you which values come from which modules - it just throws the whole module list at you. So, you can also use .definitionsWithLocations for a clearer visualization.

If your NixOS config does not use flakes (yes, I’m using nix eval here because nix-instantiate sucks doesn’t output helpful JSON for complex data types):

nix eval --experimental-features 'flakes nix-command' --impure \
   --expr 'with (import <nixpkgs/nixos> {}); options.environment.systemPackages.definitionsWithLocations' \
  -I nixos-config=/etc/nixos/configuration.nix --json | nix-shell -p jq --run jq

Or if it does use flakes:

nix eval /etc/nixos#nixosConfigurations.$(hostname).options.environment.systemPackages.definitionsWithLocations --json | nix run nixpkgs#jq

In either case, obviously replace the path to your config if it’s not located in /etc/nixos.

If the store path is not part of your config, then use nix-store --query --roots /nix/store/whatever and go from there. You can also use --deriver instead of --roots to get the store derivation but you won’t get the actual nix expression that created it.

Or if it does use flakes:

nix eval /etc/nixos#nixosConfigurations.$(hostname).options.environment.systemPackages.definitionsWithLocations --json | nix run nixpkgs#jq

This is very interesting and extremely useful (my NixOS configuration is indeed part of a flake). Thanks. I am slowly getting the hang on how Nix works :slight_smile:

However (and quite inexplicably) I can still find some packages in my path which are absent in the output of that command. For instance, waybar is in my path, and is not mentioned everywhere in the output of your command. $ which waybar:

/etc/profiles/per-user/sh4k0/bin/waybar

Which in turn is a symlink to a path in the Nix store:

lrwxrwxrwx - root  1 Jan  1970 /etc/profiles/per-user/sh4k0/bin/waybar -> /nix/store/wdjh2schdgv9h0c632qa9185zjw96jdj-home-manager-path/bin/waybar

I assume it doesn’t pop up because it’s provided by an expression within Home Manager, and not NixOS.
How can I investigate the environment provided by home-manager in a similar way?
Here is a trimmed version of my flake.nix:


{
  description = "sh4k0's NixOS config";

  inputs = {
    nixpkgs = {
      url = "github:nixos/nixpkgs?ref=nixos-unstable";
    };
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = {
    self,
    nixpkgs,
    home-manager,
    ...
  } @ inputs: let
    inherit (self) outputs;
  in {
    # NixOS configuration
    nixosConfigurations = {
      erebus = nixpkgs.lib.nixosSystem {
        specialArgs = {inherit inputs outputs;};
        system = "x86_64-linux";
        modules = [
          ./hosts/erebus
          home-manager.nixosModules.home-manager
        ];
      };
    };
    # Home-manager standalone configuration
    homeConfigurations = {
      "sh4k0@erebus" = home-manager.lib.homeManagerConfiguration {
        pkgs = import nixpkgs {system = "x86_64-linux";};
        extraSpecialArgs = {inherit inputs outputs;};
        modules = [
          ./home/home.nix
        ];
      };
    };
  };
}

Here’s what I tried, following your example (with no success):

nix eval ~/.repos/nixcfg#homeConfigurations.sh4k0@erebus.home.packages.definitionsWithLocations --json | nix run nixpkgs#jq > test.json

That’s not systemwide. If it’s via HM as you said then use the hm option in the command, home-manager.users.$(whoami).home.packages iirc if you’re using HM as a NixOS module.

I can’t tell what’s going on with your config, you have both standalone HM and HM-as-NixOS-module there, best get that sorted first.

Also your command fails because you’re missing the options. (...options.home.packages...)

I can’t tell what’s going on with your config, you have both standalone HM and HM-as-NixOS-module there, best get that sorted first.

Yes that was intended, so I can deploy my user environment either on non-NixOS hosts (as standalone HM) and as a NixOS module on NixOS hosts (as a NixOS module). Is there something wrong?

EDIT: I can’t get this to work. My home-manager configuration is sourced in my NixOS config as a NixOS module (home-manager.users.sh4k0), which also contains the packages of my user environment (home-manager.users.sh4k0.home.packages). Why does the command below not work?

nix eval ~/.repos/nixcfg#nixosConfigurations.$(hostname).options.home-manager.users.sh4k0.home.packages.definitionsWithLocations --json | nix run nixpkgs#jq > test.json

Also (going back to the original question): assuming a NixOS module with unneeded packages pre-included (like the example above), what would be the best approach to get rid of them? Only thing I can think of is writing a custom module…

Okay, just making sure you’re not using the NixOS module and standalone on the same system.

What do you mean “not work”? What is the error? (Remove the | jq bit)

Set the option, as mentioned. default has the lowest priority.

All option definitions that do not have the lowest priority value are discarded. By default, option definitions have priority 100 and option defaults have priority 1500.

What do you mean “not work”? What is the error? (Remove the | jq bit)

Sorry - you are right:

error: flake 'git+file:///home/sh4k0/.repos/nixcfg' does not provide attribute 'packages.x86_64-linux.nixosConfigurations.erebus.options.home-manager.users.sh4k0.home.packages.definitionsWithLocations', 'legacyPackages.x86_64-linux.nixosConfigurations.erebus.options.home-manager.users.sh4k0.home.packages.definitionsWithLocations' or 'nixosConfigurations.erebus.options.home-manager.users.sh4k0.home.packages.definitionsWithLocations'

Same goes trimming the command removing the json formatting.