Any difference in using niv via overlay vs importing sources

I’m concerned my home-manager config might not be using niv pinned version.

Is there semantic difference between just importing the source and setting the overlays?

My home-manager file currently uses niv like:

{ pkgs, ... }:
  sources = import ./nix/sources.nix;
  # TODO use niv for emacs-overlay
  emacs-overlay = builtins.fetchTarball "";
  pkgs = import sources.nixpkgs { overlays = [ (import emacs-overlay) ]; };
  nivpkg = import sources.niv {};
  home-manager = import sources.home-manager { pkgs = pkgs; };
  doom-emacs = import ./doomemacs.nix { sources = sources; pkgs = pkgs;};

  programs = {
    home-manager.enable = true;

  home = {
    packages = with pkgs; [ doom-emacs fd ripgrep source-code-pro sqlite gnumake nox gcc coreutils cmake graphviz nivpkg.niv libnotify];

  services = {
    lorri.enable = true;
    syncthing = {
      enable = true;


I’m concerned though since niv’s readme says to use overlays to import sources like:

{ sources ? import ./sources.nix }:     # import the sources
  { overlay = _: pkgs:
      { niv = import sources.niv {};    # use the sources :)
import sources.nixpkgs                  # and use them again!
  { overlays = [ overlay ] ; config = {}; }

If you don’t use the overlay like this, are other things perhaps not using my niv controlled nixpkgs?

How would I translate my example to the overlay version? Is it worth doing?

1 Like

I’d like to know that, too :wink:

import just “reads and evalutes” a file or directory. That being said, i think the main question is just “Any difference in using overlay vs importing?”

An overlay is kind of like mount points, they will “overwrite” the packages that were there before, where as just importing allows you to reference the package directly. Where this matters most is if your pinned package is a dependency of other packages, then an overlay will substitute all references to package with the pinned package. Where as an import will not.

An example would be if you pinned gcc with an overlay, then pretty much all packages will be rebuilt with the pinned gcc package. Where as just importing a different gcc version will allow you reference it, but it won’t be used to create other packages.

EDIT: clarity


Thank you for the nice and clear answer, learned something today :slight_smile:

Also, the main reason why I wanted to know was, that I had a problem:
Whatever version I selected via niv add/update/modify, the version of the installed package just remained the same.

Today I found that I was using the version option of niv instead of the branch option, and that the version was just a meaningless meta data in this case.

Took me half a day :confused:

So, to everyone out there, if the dependency versions of niv managed deps that are pulled of Git(hub) look suspicious, don’t be mislead by the version field but instead use the -b niv option and pass the git-branch/tag/commit-id of the version you intend to depend on.

I created a video going over how an overlay is used. In this example, I fix a broken tensorflow package: