How is Hakyll?

By Ev Bogue - December 11th 2013

[Note: I no longer use Hakyll for this site. While Hakyll is excellent, I eventually found a Node.js static site generator that suited my needs.]

Over the past few days I’ve transitioned evbogue.com to Hakyll, a static website generator written in Haskell.

A number of people have asked questions about this. Why did I switch off Node.js? Why Hakyll? How is Hakyll?

I hope to answer these questions in this piece. I will attempt to provide installation instructions for an Arch Linux VPS.

I have to stress that switching to Hakyll is an experiment. I’ve used Hakyll for two days so far, so my findings are all preliminary. I might change my mind and switch to something else – don’t jump on the bandwagon just yet if you have any hesitation!

Why Hakyll?

I was inspired to try Hakyll because of Gwern. Gwern is one of those websites on the Internet I keep going back to again and again, because every time I go there I find a new nugget of information I didn’t see before. Gwern is handling a lot of content (more content than I would ever put on a website) in a graceful way. This convinced me that Hakyll was robust. Gwern has been using Hakyll for a long time, without switching to another tool. I took this as a sign that Hakyll works for him, and that it might work for me too. Gwern explains his website choice on his about page.

Previous to Hakyll, I used a realtime website generator called Bitters that I developed with Gwen Bell as we were learning Node.js. Deploy Node explains how to create this realtime website generator from scratch.

One of the frustrations I had with Bitters, and perhaps Node.js, is I never could find a way to render a whole bunch of routes using markdown files in a folder. No matter how many ‘brilliant’ Node.js programmers I asked about how to do this, no one could answer me with a straight answer or provide a patch that would add this functionality. So adding routes to new documents in Bitters continues to be a pain.

The reason I created Bitters in the first place was there was no decent website generator written in Node.js. Very few Node.js developers ‘eat their own dogfood’ and use the Node.js for their own websites. Being that Node.js is an http server you can program with JavaScript, I imagine one simple usage of it would be to use it for your website. This is either a failure of developers, or a failure of the software. I’m not sure which yet.


  • I want to experience the workflow of a static website generator that works well. Hakyll, after my two days of usage, appears to have an ideal workflow for a static website.
  • I want to learn more languages. Haskell seems to be fringe enough that few people know it, and mature enough that useful programs have been written in it. I’m also experimenting with using xmonad instead of dwm, because I can program xmonad on the fly with Haskell.

Installing Haskell

Haskell is not without it’s own headaches. Where Node.js has callback hell, Haskell has dependency hell. While the Hakyll workflow, once it’s installed, is more than ideal, installing Haskell is less than ideal.

To get Haskell to work on your Arch Linux system, you will need to add the Arch-Haskell repository above Arch-Extra in /etc/pacman.conf. Then you will need add the pacman-key for the lead Haskell developer for Arch. Then you will need to update your keyring. If all of this is confusing to you, Deploy Arch Linux is a good place to start if you want to get more familiar with the Arch Linux ecosystem. Read the Haskell Package Guidelines for Arch Linux for more information.

I also tried installing Haskell on Debian and Fedora, and I ran into installation problems. Haskell has some strange dependency issues. Once I got familiar with them, it became easier to get Haskell to install on my systems.

Here’s how I got Haskell to install on Arch Linux, once I added the Arch-Haskell repository.

$ sudo pacman -Syu ghc cabal-install

This installs the Glorious Haskell Compiler and Cabal Install.

Once you have these two binaries, you need to use Cabal to install the rest of the packages. Do NOT install Haskell Packages from AUR. This is a terrible experience.

Cabal Install’s job is to track libraries. However, some Haskell applications depend on Haskell programs. Cabal won’t know if a Haskell program depends on another Haskell program. If you don’t know this going in, you won’t know you have to install alex and happy before you can install Hakyll. Do this now, and not after you get error messages.

$ cabal update

If cabal offers you the option of updating cabal, don’t do it. Instead proceed to the next step.

$ cabal install happy alex

This will install Happy and Alex.

Next, you’ll be free to install Hakyll.

$ cabal install Hakyll

If you’re on a desktop your install should finish and Hakyll will be installed.

If you’re on a VPS, you’ll run into your next problem.

The problem is: GHC takes up so much memory, your installation with probably get a SIGKILL if you’re using a VPS with limited RAM. A SIGKILL means you ran out of memory and the virtualization software tells the application to shut down. This will probably happen for you at the point when you’re installing pandoc, a requirement of Hakyll.

To overcome this problem, you’ll need to add a gigabyte of swap memory to your VPS. Swap memory is virtual memory on your hard disk.

Here’s how I did this on Arch Linux.

$ sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile

You just created a gigabyte of swap memory, which will buffer your install with extra virtual memory so your install doesn’t get a SIGKILL.

Overwhelmed yet? Well, then stick with Node.js, it’s way easier to install your dependencies. Otherwise, let’s continue.

The Hakyll workflow

The Hakyll workflow is pretty simple. Run

$ hakyll-init 

to start a new project. If hakyll-init doesn’t work, make sure ~/.cabal/bin is in your $PATH by typing

$ export PATH=$PATH:~/.cabal/bin

This will add the path where Hakyll is located to your $PATH in Linux.

Inside your new project folder, you’ll see a number of files.

  • ‘site.hs’ is the Haskell file where you can program your static site in Haskell
  • ‘posts’ is where your posts go, in .md format if you want
  • ‘templates’ is where your templates are. Write your templates in plain old HTML with Haskell-y partials
  • ‘css’ is where your CSS files go
  • ‘images’ is where your images go

Edit these files into a site you want to look at, and then you’ll want to render them using Haskell into a static website.

First, you’ll need to compile your site.hs file into a binary

$ ghc --make site.hs

Then you’ll want to build your site

$ ./site build

and then you want to preview your site

$ ./site watch

If these commmands don’t work, you’ll need to use prefix your command with LANG=en_US.UTF-8, like so

$ LANG=en_US.UTF-8 ./site build

Or set your global language setting for this change to be permanent

$ export LANG=en_US.UTF-8

If anything goes wrong, do a clean

$ ./site clean

When you do a build, it will put your static website in ‘_site’. Then you’re free to serve this static website however you want, using any webserver you want. I’m using lighttpd right now. You could choose to use a Node.js static website, or use the included preview webserver that comes with Hakyll.

What do you think about Hakyll?

Code elegance over user convenience →

← A brief guide to modern blogging