How I build my website
My website is made with Zola and built with a Nix Flake. I also build a PDF version of my CV with Pandoc automatically. It's hosted in GitHub pages, and built with a GH action.
I've taken the Nix pill, and while it's sometimes hard to swallow, and the UX isn't great, the benefits are pretty amazing. It allows for everything to be declarative, so the builds are always reproducible.
Since it's a standard Zola project - which uses the tabi theme, it has content
, static
, templates
, etc... directories, which the command zola build
uses to build a website and put it in a public
directory.
This is the flake.nix
file. A flake, among other things, declares inputs and locks them, so you get reproducibility in your builds.
{
description = "Personal website for praguevara";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
utils.url = "github:numtide/flake-utils";
theme = {
url = "github:welpo/tabi";
flake = false;
};
};
outputs =
inputs@{
self,
nixpkgs,
utils,
...
}:
utils.lib.eachSystem
[
utils.lib.system.x86_64-darwin
utils.lib.system.x86_64-linux
utils.lib.system.aarch64-darwin
utils.lib.system.aarch64-linux
]
(
system:
let
pkgs = import nixpkgs {
inherit system;
};
in
{
packages.website = pkgs.stdenv.mkDerivation {
name = "website";
src = self; # 'self' refers to the flake's source
buildInputs = [
pkgs.nodePackages.prettier
pkgs.pandoc
pkgs.zola
(pkgs.texlive.combine {
inherit (pkgs.texlive)
scheme-basic
etoolbox
enumitem
underscore
parskip
xcolor
sectsty
;
})
];
buildPhase = ''
# Generate the PDF from cv.md
pandoc self/content/cv/cv.md -o static/pablo_ramon_guevara_cv.pdf --template self/jb2resume.latex
mkdir -p themes
ln -s inputs.theme themes/tabi
# Copy config.toml directly from src
cp self/config.toml config.toml
cp -r self/content/ content/
cp -r self/templates/ templates/
cp -r self/static/ static/
zola build
prettier -w public '!**/*.{js,css}'
'';
installPhase = ''
mkdir -p $out
cp -r public/. $out/
'';
};
defaultPackage = self.packages.system.website;
apps.default = utils.lib.mkApp { drv = self.packages.system.website; };
devShell = pkgs.mkShell {
buildInputs = [
pkgs.nixpkgs-fmt
pkgs.zola
pkgs.pandoc
pkgs.nodePackages.prettier
];
shellHook = ''
mkdir -p themes
ln -s inputs.theme themes/tabi
'';
};
}
);
}
The relevant sections of the flake are:
Inputs: the whole nixpkgs version 24.05, from which I grab prettier, pandoc, zola and texlive. I also use
flake-utils
, and a custom input calledtheme
, which points to thetabi
repository even though it's not a flake.Derivation: the part that's in between curly brackets after
mkDerivation
. In the buildInputs I define what packages are necessary to build the site. Then, the magic happens in thebuildPhase
, where I generate the CV using pandoc, copy the relevant files and directories and build the site. After it's built, theinstallPhase
copies thepublic
directory to the$out
variable, which points to the output of the derivation.Development shell: this section declares what packages are available and what actions are run when you run the
nix develop
command. This allows me to runzola serve
to test changes. I also use direnv withuse flake;
in my.envrc
, which runs the command automatically when I cd into it.
When I run a git push
, the following GitHub action is triggered:
name: Build and Deploy to GitHub Pages
on:
push:
branches:
- master
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v27
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
nix_path: nixpkgs=channel:nixos-24.05
extra_nix_config: |
trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
substituters = https://hydra.iohk.io https://cache.nixos.org/
- name: Build Site with Nix
run: nix build .#website
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./result
publish_branch: gh-pages
force_orphan: true
It takes 2 minutes to run.
Nix really shines here. Install, run nix build .#website
and deploy. You always use the same command, regardless of the complexity of the build process.
By the way, I took inspiration from this post to create my flake originally. You should give it a look (it's quite short).