What is the best dev workflow around nix-shell?

I’ve mixed many ideas from tutorials (like haskell-nix & nix-haskell-monorepo) and approaches posted here, so this is my setup for nix-shell development as of now:

  1. Pin a working version of nixpkgs-channels with the nix-prefetch-git command, save the output as a json file.
$ nix-prefetch-git --rev 8d1510abfb592339e13ce8f6db6f29c1f8b72924 https://github.com/NixOS/nixpkgs-channels.git > .nixpkgs-version.json

Create a pinned-nixpkgs.nix file to load the json file and return our chosen version of nixpkgs:

{ bootstrap ? import <nixpkgs> {}
, json ? ./.nixpkgs-version.json
}:

let
  nixpkgs = builtins.fromJSON (builtins.readFile json);
  src = bootstrap.fetchFromGitHub {
    owner = "NixOS";
    repo = "nixpkgs-channels";
    inherit (nixpkgs) rev sha256;
  };
in
  import src {}
  1. (OPTIONAL) Create a defaul.nix. This one is my default for a simple Haskell project, for Python it would be something like buildPythonApplication. Also, it’s good to use nix-gitignore (or other similar tools) to prevent unwanted files/folders to be part of the nix-build/nix-shell (specially if you plan to use step 4).
{ pkgs ? import ./pinned-nixpkgs.nix {} }:
let
  gitignore = pkgs.nix-gitignore.gitignoreSource [] ./.;
in
pkgs.haskellPackages.callCabal2nix "<project-name>" gitignore {}
  1. Write a shell.nix file that uses your pinned version of nixpkgs, if a default.nix is present, then override it some extra dependencies that might be useful while developing your package.
let
  pkgs = import ./pinned-nixpkgs.nix {};
  dev-pkgs = with pkgs.haskellPackages; [
    cabal2nix
    cabal-install
    ghcid
    stylish-haskell
    hindent
    hlint
  ];
in
(import ./default.nix {}).overrideAttrs (old: {
  buildInputs = old.buildInputs ++ dev-pkgs;
})
  1. (OPTIONAL, but extremely useful) Use direnv with the Persistent cached shell created by @Mic92. This is one easy way to your shell from being garbage collected, you can still delete a cached env by running rm .direnv/env-*.

Change the last line from:

use_nix -s shell.nix -w .nixpkgs-version.json

to

use_nix -s shell.nix

then

$ direnv allow
2 Likes

Perfect. That did exactly what I wanted, i.e., kept Nix Clang out of the environment. It still put coreutils, bash, and a bunch of other things on the path, but those have not caused me any grief yet.

Thank you.

1 Like

My function for direnv is also maintained in this repository

1 Like

you may also be interested in lorri GitHub - target/lorri: Your project's nix-env which is a daemon which will attempt to build your expression in the background. Also I believe it manages it’s own gc-roots, so your less likely to clean your environment.

2 Likes