Append to a list in multiple imports in configuration.nix

I’d like to split my configuration.nix in a way that every file imported, will add certain packages to environment.systemPackages.

How do I do this?

I tried to write inside one of those files:

  environment.systemPackages = config.environment.systemPackages ++ with pkgs; [
    myPackage
  ];

But I get an error:

error: attribute 'environment.systemPackages' at /etc/nixos/desktop-oriented.nix:53:3 already defined at /etc/nixos/test-import.nix

Python for example, has myList.append(value) (!) How come Nix doesn’t have it?

I think the module system will merge the list for you? So you can just specify environment.systemPackages = [...] then import them.

Yeah modules are merged, so just declare your own modules (as opposed to importing several files using import and merging them together with //).

To give you an example from my own configuration:

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      # My custom modules
      ./unison.nix
      ./unifi.nix
      ./caddy.nix
    ];

  environment.systemPackages = with pkgs; [
    # …
  ];

  # rest of core config
  # …
}

And then e.g. ./unison.nix looks like

{ config, pkgs, ... }:

{
  config = {
    environment.systemPackages = [
      pkgs.ocamlPackages.unison
    ];

    nixpkgs.config.unison.enableX11 = false;
  };
}

The module system will then merge the config from my unison.nix module with the core configuration.

4 Likes

Excellent, thanks!

I understand that for my specific use case, this is the way to go. Yet how come there is no “append to list” function - it seems like such a basic expectation out of a programming language…

You’re looking for ++.

I’m familiar with the ++ operator. I think I understand now that the “problem” is that nixos-rebuild expects to see only 1 assignment to environment.systemPackages… I guess I can append a list in a nix repl but it doesn’t mean the same can be applied within a `configuration.nix.

There are two things that you’re probably not understanding here

  1. Nix values are immutable, meaning that you don’t get to change a value after you created it. It’s designed that way. It allows Nix to be lazy, meaning that you can only evaluate a part of a value, which allows Nixpkgs to be a huge attrset without you having to evaluate it in whole each time (and failing half way due to erroring expressions), and also allow circular definitions found in callPackage and overlays etc. Also by the way you risk offending the entire functional programming community saying that append to list is ‘such a basic expectation out of a programming language’.
  2. environment.systemPackages = foo; is not ‘assign foo to environment.systemPackages’. See here Nix lang: short syntax to add element to a list - #10 by dramforever.