A module (or config file) that adds config options, system packages and python packages

My NixOS configuration currently is disorganized. For example, I have installed sway, but all sway-related config goes into several different places, and I want to move it all into a single place.

In particular, I have in my configuration.nix

{ config, pkgs, ... }:

let
  my-python-packages = python-packages: with python-packages; [
    numpy
    ...
    i3ipc
    ...
  ];
  python-with-packages = pkgs.python310.withPackages my-python-packages;
in
{
  environment.systemPackages = with pkgs; [
    ...
    python-with-packages
    mako  # I know I can put that in programs.sway.extraPackages - I put it here mostly for demonstration purposes
    ...
  ];
  ...
  programs.sway = {
    enable = true;
    ...
  }
  ...
}

I also use home-manager and have a home.nix with additional sway-related options:

{ inputs, config, pkgs, ... }:
{
  ...
  programs.sway = { ... };
  ...
}

I use flakes if it’s relevant.

So I’d like to make a separate file that contains all sway configuration in a single separate file (probably would be a module, but I’m open to other solutions) which:

  • Sets the system and home-manager options - I know how to do that, what’s causing me problems are the next two points.
  • Adds i3ipc to my python installation (it has other packages like numpy specified elsewhere)
  • Adds mako to my system packages without using programs.sway.extraPackages. I will use that option in my final config, but I’d like to figure out how to add a system package from a custom module or a separate file

I looked at this example, nixos-config/i3.nix at 13d46b85e7317ac7dc748f6b50cdb5dc9cdfad2c · bobvanderlinden/nixos-config · GitHub,
which demonstrates well how to handle the first point, but not the other two.

What would be a good approach here?

Your first and last questions are trivial, even more so than what is in that link - you don’t need to create an option to do this.

Nixpkgs’ module system will “merge” modules included through imports, i.e., if you have something like this in your configuration.nix:

{config, pkgs, ...}: {
  imports = [ ./sway.nix ];

  # <other config>
}

And then put all your sway configuration in sway.nix, just as if it was in configuration.nix it would already work. This also works for lists like environment.systemPackages, the module system will simply append all the lists together.

If there is a conflict, nix will tell you and ask you to use lib.mkOverride to decide which option should take priority. But this is unlikely, since you probably won’t put sway configuration in multiple places.


The tricky bit is the additional python package. For this you could indeed create a pythonPackages option, make the module system do its merging on that list, and then set your python with that list.

I always wonder why such an option doesn’t exist in NixOS yet. A programs.python with programs.python.extraPackages and programs.python.package would make the whole python env setup thing so much less confusing for new users, and also solve this particular problem.

Maybe I should create a PR? Anyone here know why it’s not the case yet?

Ah, that’s easier than expected. Thanks.

As for programs.python, yea, such an option would make setting it up much easier without all the googling.

I don’t know if the python would be usable with services.jupyter.kernels, or you’d need to define a python-with-packages anyway for jupyter.

You could probably use config.programs.python.package, assuming there is a packageBase to override the base python, and the full package gets resolved into package. config refers to the fully resolved attributes, in case you didn’t realize :slight_smile:

Hi, can you make some clarifications?

First, for home-manager config, would it be just home-manager.users.${username}.some_option = "option_value"?

Second, I tried your suggestion for the python-packages, but I hit a snag. The issue is, the way I’ve seen them done is,

  my-python-packages = python-packages: with python-packages; [
    numpy
    ...
    i3ipc
    ...
  ];
  python-with-packages = pkgs.python310.withPackages my-python-packages;

So, I don’t actually have a list to auto-merge, but rather a function that returns a list. I’m not sure how to do that. Maybe I should make the option be list of strings, but then
how to get the actual packages to pass to pkgs.python310.withPackages?

Something like

pkgs.python310.withPackages (python-packages: 
  map    
    (pname: builtins.getAttr pname python-packages)
    config.my-python-packages
);

This may well be why there is no such option in nixpkgs yet, it feels a bit dirty to use strings for this.

There’s actually a lib function that does that map for you, if you prefer:

pkgs.lib.attrVals config.my-python-packages python-packages

Since nix has partial function application that means you can simplify it to this (I think):

pkgs.python310.withPackages (pkgs.lib.attrVals config.my-python-packages);

Probably not, you might want to have a read of this section of the home manager manual: Home Manager Manual