Skip to content

Use packages from flakes

Warning

This is based on the basic VM and we will only pay attention to the changes required to have the VM use packages defined by other flakes.

Overview

To install packages from another flake into the VM, we need to do the following:

  1. Add the other flake(s) as input(s) to our flake
  2. Pass the inputs to the NixOS configuration file (configuration.nix)
  3. Right now, only pkgs (effectively nixpkgs) is passed along
  4. Add the packages to install to the environment.systemPackages list

Setup

Add new flake as input

In this example, we will install libvfn and xnvme, which as of writing are not available in nixpkgs. They are available as packages in the flake github:nix4noobs/pkg-c-meson/master:

add a new flake as input
inputs = {
    # ...
    nix4noobs-pkg-c-meson.url = "github:nix4noobs/pkg-c-meson/master";
    # ...
};

Pass flake inputs to configuration.nix

Presently, configuration.nix, which holds the NixOS configuration of our VM, only gets the pkgs argument, which itself is an alias of the nixpkgs input.

Looking at configuration.nix, we see that the file contains a single Nix expression, which is really a function taking an attribute set (which must have a pkgs attribute), and returning another attribute set, the NixOS configuration.

outline of configuration.nix
{ pkgs, ... }: {
    # ...
}

You could view the type signature of configuration.nix as { pkgs, ...} -> { ... } where the latter is the attribute set containing the configuration of our NixOS VM.

In flake.nix, we have the following:

call to nixosGenerate
vm = nixos-generators.nixosGenerate {
  system = pkgs.system;
  modules = [
    # add configuration.nix here
    ./configuration.nix
  ];
  format = "qcow";
}

The first thing to do, is to change ./configuration.nix (a path) into (import ./configuration.nix { inputs = self.inputs; }). import is a builtin function which parses the given file and returns its nix expression. In this case the full function we discussed. Secondly, we use the self argument which references the flake itself, to get the inputs attribute set - and we pass which along as an attribute set with inputs = self.inputs.

This will fail, recall configuration.nix is presently { pkgs, ... } -> { ... }, but now we need something like { inputs, ... } -> { pkgs, ... } -> { ... }. That is, we need to wrap the contents of configuration.nix in another function.

new outline of configuration.nix
{ inputs, ... }: {
    { pkgs, ... }: {
        # ...
    }
}

Now we have passed the flake inputs attribute set to our NixOS configuration, which means we can reference packages from those inputs.

Install packages from flake

After adding the two new packages, the environment.systemPackages list looks like so:

systemPackages with libvfn and xnvme added
environment.systemPackages = [
  pkgs.fortune 
  inputs.nix4noobs-pkg-c-meson.packages.${pkgs.system}.libvfn
  inputs.nix4noobs-pkg-c-meson.packages.${pkgs.system}.xnvme
];

Note that packages from flakes follow the form inputs.<flake name>.packages.<system>.<package name>. Note also that pkgs.system holds the current system. This comes from the definition of forAllSystems:

forAllSystems function
forAllSystems = fn:
  nixpkgs.lib.genAttrs allSystems
  (system: fn { 
    pkgs = import nixpkgs { inherit system; };
});

Note how pkgs is the result of calling the function returned by import nixpkgs with an attribute set where system is the current system value.