Nix Flakes and NixOS, make the process of deploying your blog simple, and reproducible.
In this post, we’ll explore how to use Nix Flakes to deploy your blog.
What are Nix Flakes?
A lot of the material on the web explaining Nix Flakes are a bit confusing at best.
I like to think of them as a recipe - they contain a description of everything you need to run a piece of software. They are somewhat similar to Dockerfiles but with a few important differences:
- Reproducibility: Nix Flakes are reproducible. They’re guaranteed to be built the exact same way every time.
- Development Environment: They can be your development environment. Everyone can use the flake and be guaranteed to be using the same compiler versions, dependencies, etc.
- Built-in Build Functionality: They sprinkle in some Makefile-like functionality into the recipe. You can run commands like
nix build
ornix run
.
The Hugo Blog
Now that we understand what a Nix Flake is, let’s look at a practical example: deploying my blog.
I want my blog powered by Hugo, so let’s get that setup first.
{
description = "Glenn McDonald's Blog";
# Inputs section specifying dependencies for the flake, aka imports
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
# Outputs defines what this flake provides
outputs = { nixpkgs, flake-utils, ... }:
# Helper functions for compatibility across different system architectures
flake-utils.lib.eachDefaultSystem (system:
# Import the nixpkgs collection for the current system
let pkgs = import nixpkgs { inherit system; };
in {
# Define the development shell environment
devShell = pkgs.mkShell {
# Specify what packages we want available in our development shell
# This could be things like linters, cli tooling, compilers etc.
buildInputs = [ pkgs.hugo ];
};
});
}
Now we can run nix develop
and you’ll be dropped into a shell with Hugo available!
hugo new site flake-blog
Now that we have our Hugo scaffolding setup, let’s get it building using Nix Flakes.
{
description = "Glenn McDonald's Blog";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
# Inputs don't have to be other flakes, it can be anything!
# We'll use this to fetch the Hugo theme we want
devise = {
url = "github:austingebauer/devise";
flake = false;
};
};
outputs = { self, nixpkgs, flake-utils, ... }@inputs:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs { inherit system; };
in {
# Define the packages that this flake provides, in this case our blog
packages.website = pkgs.stdenv.mkDerivation {
name = "blog";
# The directory of the package, self is the directory of the Flake
src = self;
# Build inputs required for building our package, this could be things like
# openssl, gcc, etc
buildInputs = [ pkgs.git ];
# Our build step instructions
# We want to add a custom theme, so we'll make that directory and move the input contents in there
# Finally we'll call hugo to generate the static files
buildPhase = ''
mkdir -p themes
ln -s ${inputs.devise} themes/devise
${pkgs.hugo}/bin/hugo
'';
# What to do once the package is built
installPhase = "cp -r public $out";
};
# Define the default package to be built, a flake could have multiple packages
defaultPackage = self.packages.${system}.website;
devShell =
pkgs.mkShell { buildInputs = [ pkgs.hugo ]; };
});
}
Now we’ve defined our Hugo package we can run nix build
which will run the steps we’ve defined.
If you run ls
in our blog directory now we should should see a result symlink which points to our built Hugo blog!
In my follow up post I’ll explain how to use this package in a NixOS configuration, which will serve it with Nginx.