Correct way to use <nixpkgs> in nix-shell on flake-based system without channels

Since moving to a flake based setup (for both system and user (home-manager)) I can (and should?) not register channels anymore (I suppose), to make sure my sources are in sync.

However, I still want to use my “standard” shell.nix definitions, which refer to <nixpkgs> (and I would like to add nixpkgs-unstable too).

Does this mean I should be looking for a way to make sure nixpkgs=... is somehow put in my NIX_PATH env by application of my flake, such that it refers to the same path that is downloaded by my flake based on the flake inputs?

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11";
    nixpkgsUnstable.url = "github:NixOS/nixpkgs/nixos-unstable";

    home-manager = {
      url = github:nix-community/home-manager;
      inputs.nixpkgs.follows = "nixpkgsUnstable";

    nurpkgs = {
      url = github:nix-community/NUR;
      inputs.nixpkgs.follows = "nixpkgs";

What is the “correct” way to achieve this?

the main idea is to put the outPath of the nixpkgs flake input into NIX_PATH, indeed.
i.e. home.sessionVariables.NIX_PATH = nixpkgs.outPath (home-manager) or nix.nixPath = [ "nixpkgs=nixpkgs.outPath" ] (nixos).

you can also use GitHub - gytis-ivaskevicius/flake-utils-plus: Use Nix flakes without any fluff. so that your current nixpkgs is always findable at /etc/nix/inputs/nixpkgs (or whatever the home-manager equivalent is), and point NIX_PATH there.

1 Like

Thanks, that seems to work nicely.

For my case I needed to add a level of indirection, since I’m passing the imported nixpkgs to my configuration.nix and home.nix, so I did

  unstable = import inputs.nixpkgsUnstable {
    inherit system;
    config.allowUnfree = true;
    overlays = [] ++ (import ../system/overlays/default-unstable.nix);
  } // { outPath = inputs.nixpkgsUnstable.outPath; };

and then (for system/root)

nix.nixPath = [ "nixpkgs=${pkgs.outPath}" "unstable=${unstable.outPath}" ];

and for HM:

home.sessionVariables.NIX_PATH = "nixpkgs=${pkgs.outPath}:unstable=${unstable.outPath}";

But: is it ok to “just” overwrite the NIX_PATH like that? Or should I rather be adding to it?

I only set nix.nixPath at the system level, and then my normal user inherit that, without the need to go through home.sessionVariables.NIX_PATH.

It seems this behaviour is defined here.

So it appears you don’t need to do anything for HM.

well, I like to pretend that my HM config is usable outside NixOS too (not that I’ve actually tested that in like a year), otherwise yes.

Funny, for me it didn’t work even though I expected that, meaning after su - checking env | grep nixpkgs it was good, but as a user the result was empty. I then added the HM part which made it work.

My first try was (btw) to try to assign the path directly in the import statement like this, but that didn’t work, presumable because nixPath is/can be overwritten somewhere (?):

  unstable = import inputs.nixpkgsUnstable {
    inherit system;
    config.nix.nixPath = [ inputs.nixpkgsUnstable.outPath ];
    config.allowUnfree = true;
    overlays = [] ++ (import ../system/overlays/default-unstable.nix);

As for the specific HM config, this appears to work for <nixpkgs> but not for <unstable> even though I’d have expected it to be passed transparently (from reading your link)… I don’t understand why.

You should change


config.nix.nixPath = [ "unstable=${inputs.nixpkgsUnstable}" ];