What shall I do if I want to add a package, but do not want to touch nixpkgs tree?

The standard way is to put some .nix file in the tree of nixpkgs. This seems to require maintaining a nixpkgs repository. However, I may meet some problems in which I need to temporarily add a package into the system path i.e., nix/store, in a stateless way.

I guess that it is possible to include the package definition files in the configure.nix. After run the nixos-rebuild switch, the package can be installed. Next time if I remove the definition, and run the nixos-rebuild again the package can be removed. Is it possible to do this and is it a proper way to do this?

Thanks.

It is perfectly fine to just inline the package definition into environment.systemPackages in your configuration.nix:

# configuration.nix
{ pkgs }:
{
  environment.systemPackages = [
    (with pkgs; stdenv.mkDerivations {
      # …
    })
  ];
}

or if you prefer slightly cleaner

# configuration.nix
{ pkgs }:
{
  environment.systemPackages =
    let
      mypkg = (with pkgs; stdenv.mkDerivations {
        # …
      });
    in [
      mypkg
    ];
}

Or if you want to pass it to multiple options, you can define it in wider scope.

# configuration.nix
{ pkgs }:
let
  mypkg = (with pkgs; stdenv.mkDerivations {
    # …
  });
in {
  environment.systemPackages = [
    mypkg
  ];
  systemd.packages = [
    mypkg
  ];
}

If you like to keep your configuration.nix clean, you can move the package definition to a separate file:

# configuration.nix
{ pkgs }:
{
  environment.systemPackages = [
    (import ./pkgs/mypkg { inherit pkgs; })
  ];
}
# pkgs/mypkgs/default.nix
{ pkgs }:
stdenv.mkDerivations {
  # …
}

And if you expect you will want to move the package to nixpkgs later, you might as well use the convention of accepting dependencies as separate arguments:

# configuration.nix
{ pkgs }:
{
  environment.systemPackages = [
    (pkgs.callPackage ./pkgs/mypkg { })
  ];
}
# pkgs/mypkgs/default.nix
{ stdenv, foo, bar }:
stdenv.mkDerivations {
  # …
}

It is even nicer to use overlays, which will add the package to pkgs passed to your configuration modules. They allow, among other things, easier re-use across repositories since they can be applied over different versions of Nixpkgs.

# configuration.nix
{ pkgs }:
{
  environment.systemPackages = [
    pkgs.mypkg
  ];
  nixpkgs.overlays = [
    (import ./overlays/pkgs)
  ];
}
# overlays/pkgs.nix
final: prev:
{
  mypkgs = prev.callPackage ../pkgs/mypkgs {};
}
# pkgs/mypkgs/default.nix
{ stdenv, foo, bar }:
stdenv.mkDerivations {
  # …
}

And of course, there are many more combinations in between. Nix is an expression based language so you can easily move expressions wherever fits your style.

12 Likes