Express environment.systemPackages as a concatenation of lists

As the title suggests, I’d like to split the environment.systemPackages definition in my conguration.nix into multiple lists (i.e. shell scripts, python libraries, packages).

This is my attempt, using the string concatenation operator:

{ inputs, config, lib, pkgs, ... }:

{
    [ ... ]

    environment.systemPackages = let
        pythonPackages = [
            (pkgs.python3.withPackages (python-pkgs: with python-pkgs; [
                numpy
                jupyterlab
            ]))
        scripts = [
            (import ../../lib/script1.nix { inherit pkgs; })
            (import ../../lib/script2.nix { inherit pkgs; })
        ];
        standardPackages = with pkgs; [
            vim
            git
            gcc
        ];
    in
        {
            pythonPackages ++ scripts ++ standardPackages
        };
    }

However, the evaluation fails with the following error:

error: syntax error, unexpected CONCAT, expecting '.' or '='
       at /nix/store/nqxz5p4rrbnk73l6xp11y7kdvbpavziy-source/foo/bar/default.nix:179:15:
          178|     {
          179|       pythonPackages ++ scripts ++ normalPackages;
             |               ^
          180|     };

I think I understand the logic of let... in bindings, and I don’t see why the above expression would refuse to evaluate. Anyone has any hint?

Try replacing

{
  pythonPackages ++ scripts ++ standardPackages
};

with

  pythonPackages ++ scripts ++ standardPackages;

environment.systemPackages should be of the type “list of packages”.
The parenthesis make it as type of “attribute set”, that’s why nix throws errors

1 Like

The comment above explains the problem with your code.

However, environment.systemPackages already has exactly the behaviour you want. If you write environment.systemPackages = [ vim ]; in one file, and environment.systemPackages = [ git ]; in another file, and import both files (e.g. put imports = [ ./vim.nix ./git.nix ] in your configuration.nix), then Nix will merge both definitions and install both Vim and Git. See the Modularity section of the NixOS manual for more details.

5 Likes

@phaeseeKe5Ee: makes totally sense. I don’t know how I missed it. I thought a curly bracket was needed in order to delimit the “in…” section of the expression.

@keysmashes: thanks for the suggestion! That is actually very helpful. I might be splitting my packages in multiple files to import them accordingly :slight_smile:

You don’t even need to do that, you can explicitly mkMerge modules:

{ lib, pkgs, ... }: {
  environment.systemPackages = lib.mkMerge [
    (with pkgs; [
      vim
      gcc
      git
    ])

    (pkgs.python3.withPackages (ppkgs: with ppkgs; [
      numpy
      jupyterlab
    ])
  ];
}
1 Like

@TLATER, thank you for the suggestion. Are there some beginner-friendly resources on builtin nix functions (such as mkMerge)? So far, I only know noogle.dev (which however seems more oriented towards experienced users).

Your best bet is https://nix.dev, for these NixOS-specific functions specifically, the module tutorial.

The NixOS manual also has a section about this, but it’s also more oriented towards developers/reference manual type things.