http://techblog.holidaycheck.com/post/2017/11/14/nix-in-practice-providing-dependencies is very cool!

It's really nice when developing to have your deps pinned and not have to rebuild the world because you bumped your user profile. Also, you don't want any build errors to be able to come from some package other than what you're developing. So the post describes how to do the equivalent of your lock file in node, ruby or python, but with nix.

But to follow best practice and make your default.nix a function with default parameters, instead of doing everything in local variables with let, just use let for the bootstrap mechanism, like this:

let
bootPkgs = import <nixpkgs> { };
bootFetchgit = bootPkgs.fetchgit;
remotePkgs = bootFetchgit {
url = "git://github.com/NixOS/nixpkgs-channels.git";
rev = "a66ce38acea505c4b3bfac9806669d2ad8b34efa";
sha256 = "1jrz6lkhx64mvm0h4gky9b6iaazivq69smppkx33hmrm4553dx5h";
};
in
{ pkgs ? import remotePkgs { }
, stdenv ? pkgs.stdenv
[ . . . ]


# #