Setting the scene

After neglecting this small place on the internet for years, I cloned the repo with the hope of quickly updating my resume. This site is constructed with Hugo, which is a static site generator written in golang. Anyway, I needed to install that too, so I edited my home-manager configuration and switched, i.e., I installed it.

There was an attempt

First thing I tried was running “hugo serve” which starts a web server and serves the content of your hugo project so changes can be seen as you make them. But that failed. I don’t remember the errors; it’s not important, I knew what happened- years had passed, non-backward compatible changes had been made to hugo and something I was doing no longer worked. That’s one way of putting it. The more correct way of putting it is that I was using a much newer version of hugo for a website that was created using a previous version. This was my own mistake and this wasn’t going to happen again. This time I would fix the glitch.

Enter Nix

I created a flake.nix in the root of my project directory with the following contents.

  description = "my hugo flake with a shell";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
        pkgs = nixpkgs.legacyPackages.${system};
        devShell = pkgs.mkShell {
          nativeBuildInputs = [ pkgs.bashInteractive ];
          buildInputs = with pkgs; [ hugo awscli2 ];

This flake isn’t any good. I don’t even automate the build, but it does what exactly what I need. It pins the dependencies I need to build and deploy my project, hugo and awscli2.

I also added a .envrc file with the following contents:

 if ! has nix_direnv_version || ! nix_direnv_version 1.6.0; then
      source_url "" "sha256-FqqbUyxL8MZdXe5LkMgtNo95raZFbegFpl5k2+Pr

 use flake

Now, assuming you have nix-direnv you will be dropped into a shell with your dependencies each time you enter your project directory. In this particular case I’m using the version numbers of hugo and awscli2 as supplied by nixpkgs-unstable. This isn’t the only way to do this; you could have pinned to a particular version of hugo or awscliv2, but this is good enough for this simple project. A flake.lock file that describes how nix understands the dependencies is generated the first time you enter the directory:

    "nixpkgs": {
      "locked": {
        "lastModified": 1644972330,
        "narHash": "sha256-6V2JFpTUzB9G+KcqtUR1yl7f6rd9495YrFECslEmbGw=",
        "owner": "NixOS",
        "repo": "nixpkgs",
        "rev": "19574af0af3ffaf7c9e359744ed32556f34536bd",
        "type": "github"

I’ve abbreviated it, but you can see the git sha of the nixpkgs repo to which we are pinned. nixpkgs ( is the repo that holds our dependencies (and 80k+ software packages for nix) and the instructions of how to build them for the nix package manager.


Of course constructing your flake and .envrc is a lot of work, which is why I didn’t do it by hand. Intead, I ran flakify (I simple bash script) which I stole from, but has since been removed so here it is.

flakify() {
  if [ ! -e flake.nix ]; then
    nix flake new -t github:nix-community/nix-direnv .
  elif [ ! -e .envrc ]; then
    echo "use flake" > .envrc
    direnv allow
  ${EDITOR:-vim} flake.nix

From there I just added my two dependencies to the dev shell. ‘Course you have to have nix and nix-direnv installed.

This fixes nothing

So, yeah, I still had to change my website code to work with the new version of hugo I pulled in from nixpkgs. But from now on, I can choose when I want to do that, by updating the dependencies at a time of my choosing.


Nix flakes provide a lot more than developer shells. If you’d like to learn more, check out Xe’s intro to flakes and follow that up with xer flake packages.