Read the tutorial to get started! https://robertwpearce.com/the-hakyll-nix-template-tutorial.html
All build inputs (GHC, Hakyll, pandoc, ...) come prebuilt from the default NixOS binary cache, so a fresh clone builds without compiling the toolchain from source and needs no extra substituter setup.
If you make changes to anything inside of ssg/, you'll need to clean the
hakyll cache and rebuild. This is the preferred series of commands for
rebuilding (with logs), cleaning the cache, and re-running the dev server:
nix build --print-build-logs && \
nix run . clean && \
nix run . watch
Build your site into the ./result/dist folder:
λ nix build
Start hakyll's dev server that reloads when changes are made:
λ nix run . watch
Listening on http://127.0.0.1:8000
...more logs
Run any hakyll command through nix run .!
λ nix run . clean
Removing dist...
Removing ssg/_cache...
Removing ssg/_tmp...
Start a development environment that
hakyll-site (for building/watching/cleaning hakyll projects)hakyll-init (for generating new projects)shell.buildInputs of the
hakyllProject in flake.nixghci with some defaults and the modules loaded so you can
make your own changes and test them out in the ghci REPLλ nix develop
[hakyll-nix]λ hakyll-site build
...
Success
[hakyll-nix]λ ghci
...
[1 of 1] Compiling Main ( ssg/src/Main.hs, interpreted )
...
λ >
All of this is customizable, and here are some things that are already done for you:
slugger module is included that makes nice link URIs based on post titles?v=<hash> query string so
browsers refetch only when a file's contents change)Configure the dev server, cache & tmp directories, and more in
./ssg/src/Hakyll/Site/Configuration.hs.
Deployment runs through a GitHub
Action: every push to main builds the
site with Nix and publishes it to GitHub Pages
using GitHub's official Pages deployment (actions/deploy-pages). It publishes
straight to the Pages CDN — there is no gh-pages branch — and authenticates
with a short-lived
OIDC
token rather than a long-lived credential.
One-time setup for your fork:
CNAME file so it deploys cleanly by default;
if you prefer the file-based approach, add a CNAME file under src/ and a
copy rule for it in the forM_ list in ssg/src/Main.hs.Note: If your main branch isn't named main, update branches: [main] and the
if: github.ref == 'refs/heads/main' in ./.github/workflows/main.yml.
If you don't have nix, follow the nix installation instructions.
Once you have nix installed, follow the instructions here to get access to flakes: https://nixos.wiki/wiki/Flakes.
Haskell Language Server
needs to run inside this project's Nix dev shell (which provides the matching
GHC, the site's dependencies, HLS, hlint, and ormolu) to work in your
editor. Two ways to wire that up:
.vscode/settings.json already points it at
shell.nix (which re-exports the flake's dev shell). No extra system tooling
required — this is what the bundled .vscode/ recommends.direnv and
nix-direnv, then run direnv allow in this directory. The bundled .envrc (use flake) loads the dev
shell in your terminal and any editor with direnv integration (Emacs envrc,
vim, etc.).Both reuse the single dev-shell definition in flake.nix, and HLS loads the
Haskell project from ssg/ automatically.
This repo ships .vscode/ defaults: on first open, VS Code recommends the
Haskell
and Nix Env
Selector
extensions; .vscode/settings.json points Nix Env Selector at shell.nix and
sets haskell.manageHLS to "PATH" so the Haskell extension uses HLS from the
Nix dev shell rather than downloading its own. That HLS bundles hlint, so
lint diagnostics and "Apply hint" code actions appear automatically — no
separate linter needed. Add a .hlint.yaml at the repo root to customize the
hlint rules.
The ./.github/workflows/main.yml file pushes build results to
cachix so CI (and anyone building your site) can reuse
cached artifacts instead of rebuilding from source.
./.github/workflows/main.yml. It is currently
hardcoded to this template's cache (name: hakyll-nix-template, in the
"Build with cachix" step); point it at the cache you just created, otherwise
pushes will fail with a permissions error.CACHIX_AUTH_TOKEN secret at
https://github.com/<you>/<your-repo>/settings/secrets/actions (this is the
secret name the workflow reads).Haskell
77.2%
Nix
11.7%
HTML
7.3%
CSS
2.6%
Shell
1.0%
Read the tutorial to get started! https://robertwpearce.com/the-hakyll-nix-template-tutorial.html
All build inputs (GHC, Hakyll, pandoc, ...) come prebuilt from the default NixOS binary cache, so a fresh clone builds without compiling the toolchain from source and needs no extra substituter setup.
If you make changes to anything inside of ssg/, you'll need to clean the
hakyll cache and rebuild. This is the preferred series of commands for
rebuilding (with logs), cleaning the cache, and re-running the dev server:
nix build --print-build-logs && \
nix run . clean && \
nix run . watch
Build your site into the ./result/dist folder:
λ nix build
Start hakyll's dev server that reloads when changes are made:
λ nix run . watch
Listening on http://127.0.0.1:8000
...more logs
Run any hakyll command through nix run .!
λ nix run . clean
Removing dist...
Removing ssg/_cache...
Removing ssg/_tmp...
Start a development environment that
hakyll-site (for building/watching/cleaning hakyll projects)hakyll-init (for generating new projects)shell.buildInputs of the
hakyllProject in flake.nixghci with some defaults and the modules loaded so you can
make your own changes and test them out in the ghci REPLλ nix develop
[hakyll-nix]λ hakyll-site build
...
Success
[hakyll-nix]λ ghci
...
[1 of 1] Compiling Main ( ssg/src/Main.hs, interpreted )
...
λ >
All of this is customizable, and here are some things that are already done for you:
slugger module is included that makes nice link URIs based on post titles?v=<hash> query string so
browsers refetch only when a file's contents change)Configure the dev server, cache & tmp directories, and more in
./ssg/src/Hakyll/Site/Configuration.hs.
Deployment runs through a GitHub
Action: every push to main builds the
site with Nix and publishes it to GitHub Pages
using GitHub's official Pages deployment (actions/deploy-pages). It publishes
straight to the Pages CDN — there is no gh-pages branch — and authenticates
with a short-lived
OIDC
token rather than a long-lived credential.
One-time setup for your fork:
CNAME file so it deploys cleanly by default;
if you prefer the file-based approach, add a CNAME file under src/ and a
copy rule for it in the forM_ list in ssg/src/Main.hs.Note: If your main branch isn't named main, update branches: [main] and the
if: github.ref == 'refs/heads/main' in ./.github/workflows/main.yml.
If you don't have nix, follow the nix installation instructions.
Once you have nix installed, follow the instructions here to get access to flakes: https://nixos.wiki/wiki/Flakes.
Haskell Language Server
needs to run inside this project's Nix dev shell (which provides the matching
GHC, the site's dependencies, HLS, hlint, and ormolu) to work in your
editor. Two ways to wire that up:
.vscode/settings.json already points it at
shell.nix (which re-exports the flake's dev shell). No extra system tooling
required — this is what the bundled .vscode/ recommends.direnv and
nix-direnv, then run direnv allow in this directory. The bundled .envrc (use flake) loads the dev
shell in your terminal and any editor with direnv integration (Emacs envrc,
vim, etc.).Both reuse the single dev-shell definition in flake.nix, and HLS loads the
Haskell project from ssg/ automatically.
This repo ships .vscode/ defaults: on first open, VS Code recommends the
Haskell
and Nix Env
Selector
extensions; .vscode/settings.json points Nix Env Selector at shell.nix and
sets haskell.manageHLS to "PATH" so the Haskell extension uses HLS from the
Nix dev shell rather than downloading its own. That HLS bundles hlint, so
lint diagnostics and "Apply hint" code actions appear automatically — no
separate linter needed. Add a .hlint.yaml at the repo root to customize the
hlint rules.
The ./.github/workflows/main.yml file pushes build results to
cachix so CI (and anyone building your site) can reuse
cached artifacts instead of rebuilding from source.
./.github/workflows/main.yml. It is currently
hardcoded to this template's cache (name: hakyll-nix-template, in the
"Build with cachix" step); point it at the cache you just created, otherwise
pushes will fail with a permissions error.CACHIX_AUTH_TOKEN secret at
https://github.com/<you>/<your-repo>/settings/secrets/actions (this is the
secret name the workflow reads).Haskell
77.2%
Nix
11.7%
HTML
7.3%
CSS
2.6%
Shell
1.0%