My first nix flake!
It's happened, I've drank the punch.
So I got into dev shells a while back, but I've started to run into some issues, mostly with other's nix shell environments. QMK's shell.nix is one such issue, and I believe it has something to do with it being written for NixOS, or at least Nix on Linux. This highlights one of the biggest weaknesses of using "bare" nix as opposed to Nix Flakes, with their ability to build different targets. With that out of the way on the why I bothered, here's my first flake!
This blog!
{
description = "A flake for developing and building my personal website";
# It's a flake, may as well try the latest
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
# Useful utilities to automatically create targets for different
# platforms. Just makes it more readable in this case.
inputs.flake-utils.url = "github:numtide/flake-utils";
# This builds a package, in this case, containing zola
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
# This uses nix to fully build the site as a nix package.
packages.website = pkgs.stdenv.mkDerivation rec {
pname = "static-website";
version = "2023-08-26";
src = ./.;
nativeBuildInputs = [ pkgs.zola ];
buildPhase = "zola build";
installPhase = "cp -r public $out";
};
# This output is what we use for our dev shell.
defaultPackage = self.packages.${system}.website;
devShell = pkgs.mkShell {
packages = with pkgs; [
gnumake
zola
];
};
}
);
}
While functionally similar to the previous system without a flake, it will create a flake.lock file. Currently it looks like this, though you should never hand edit this file, I'm just showing what's in it.
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1692799911,
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1693355128,
"narHash": "sha256-+ZoAny3ZxLcfMaUoLVgL9Ywb/57wP+EtsdNGuXUJrwg=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a63a64b593dcf2fe05f7c5d666eb395950f36bc9",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
This will fully lock down all of the sources by revision of git commit, or
similar. This insures that if Zola updates, and it breaks the blog, no new
install of Zola on a new machine, or a newly spawned shell will seemingly
randomly break. This gives us the option of updating only when we are ready,
knowing that all machines are on identical versions of the software, and we can
update and push the exact same update to all machines at the same time. Updating
the flake is as simple as running nix flake update
. If everything works as
expected, then commit the new flake.lock
file to the repository and push it
like any other change to the repo.
Other upsides
Now that I have a flake, I can simply reference it from other flakes, even if I don't have it locally installed on the machine. FlakeHub is a common place that people push their flakes for others to use, as is GitHub. Flakes can be layered similar to docker images, so you can use other's flakes to build on top of to make creating tooling easier, as well as deployment of build tools! Nix can, and will, eat your everything if you let it.
Further rambling outro
While I have stated that I won't let Nix eat my everything, I'm coming around to the cool tooling that it has to offer. I doubt that I'll let it completely take over everything, but time will tell. I've still not got amazing things to say about NixOS, and quite like having a system underneath nix to run the show, but I try to give things a try before truly dismissing them. Maybe next I'll try to build docker images with nix as I'm not a huge fan of creating images the "normal" way. Still keeping docker, but changing the build tooling. We'll see I suppose.
Useful snippits that may help you out.
Make a shell package, or basic flake to start a dev environment, all in a zsh/bash function.
nixify() {
if [ ! -e ./.envrc ]; then
echo "use nix" > .envrc
direnv allow
fi
if [[ ! -e shell.nix ]] && [[ ! -e default.nix ]]; then
cat > default.nix <<'EOF'
with import <nixpkgs> {};
mkShell {
nativeBuildInputs = [
bashInteractive
];
}
EOF
${EDITOR:-vim} default.nix
fi
}
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
fi
${EDITOR:-vim} flake.nix
}
And some more reading if you want to know more. These are the resources that I used to get where I am with this post.
https://ejpcmac.net/blog/migrating-to-a-static-blog/
https://fasterthanli.me/series/building-a-rust-service-with-nix/part-10
https://zero-to-nix.com/concepts/flakes