I have been wanting to make a personal blog for some time, but it is a project that has always sat on the back burner for me. Mainly because I am not wholly interested in web development, yet I did not want to use a prepackaged, all in one blogging solution. So one day I just decided to start working at it, and after reading about many web frameworks I decided to make my blog using node.js.

The site started out simple enough, wrote some route handling, some css, some test posts, etc. But my project soon grew too big and too complex too quickly. I began the project looking for something small and simple, however the further i progressed, the longer my TODO list grew. Now maybe this inability to create a simple site with node.js brings to light flaws I have as a developer, or inexperience with the language and web development concepts. Either way I decided to table the project and look for a new platform for my blog.

Another framework I had come across in my initial search was hakyll, a Haskell library for static site compilation. I have experimented with Haskell in the past, with some project Euler problems, and simple command line programs. From what I had seen, it was a pretty neat language. So I embarked yet again on my blog development.


I use git for version control due to its relative ease of use for both code development and deployment, as well as its popularity. After creating a new git repository, you need to install hakyll. It is conveniently packaged on Hackage, so it can be installed with cabal(1). It is recommended when doing Haskell development work to use cabal sandboxes, project local dependency installation. Using cabal for installing packages globally can get messy. For more information on sandboxing see the link below. Hakyll comes with a binary, hakyll-init, which sets up an example site. This step can be skipped if you want to start from scratch, however looking at the default project files to understand how the system works is beneficial.

$ mkdir hakyll-site && cd hakyll-site
$ git init
$ cabal sandbox init
$ cabal install hakyll
$ .cabal-sandbox/bin/hakyll-init .


A default Hakyll project has the following structure:

  • site.hs - main site file which defines the routes, compilation rules, and configuration settings

  • images/ - directory containing image assets

  • posts/ - directory containing blog posts

  • css/ - directory containing css files

  • templates/ - directory containing page templates which define how pages are built into their final HTML form

The default site.hs contains the proper routing and compilation rules to get a simple blog started. After reading over the code to understand what was going on, I only had to make some minor adjustments to suit my needs. When compiling the site.hs file, the site executable becomes a valuable tool for development. You can generate the HTML with ./site build, and then start a preview server with ./site server. ./site watch can also be used, and the site files will be monitored for changes, and regenerated on the fly. Next I tweaked the css a bit to make my blog more appealing. Finally I only had to make the actual content of my website, which turned out to be the hardest and most time consuming part of this whole endeavor. Mind you coming up with the content was the difficult part, not the formatting or technical parts. There is built in support for pandoc, which allows conversion to/from HTML, markdown, and LaTex (among many others). I personally like writing in markdown, as its easy to understand and implement syntax allows for powerful, yet simple formatting.


For hosting my website I decided to host it on a VPS, running a NGINX docker container. I went with docker so the sever can easily be rebuilt, or moved to a different environment. I compile the site on my local dev machine so the Haskell libs don’t need to be rebuilt each time on my remote server. In the future I may set up some sort of automated build/deployment container using git hooks.

Hakyll has a built in option for deploying site code. You can configure a custom deployment script in site.hs, which will then execute with ./site deploy. For example:

config = defaultConfiguration
	{ deployCommand = "scp _site/* remote-server:/var/www"
./site rebuild
./site deploy


As a first(ish) experience with web development, I would rate this whole endeavor positively. Hakyll is an elegant solution for static site generation, with a simple yet powerful syntax. As my understanding of Haskell has grown throughout the course of this project, I have had many thoughts about what to change, and new features I can add to this site. After finishing a first production draft of the site I am looking forward to further development. Being a static site, I could have gotten away with simply hosting the built project on some AWS S3 buckets and called it a day, but I wanted some experience with more complex technologies that may be required in future projects. My overall impression of docker so far is okay. I see the potential it has in certain situations. NGINX is probably overkill for a simple application such as this, however it opens a door more advanced configuration and tuning options for the future.



[1]Stackage, a ‘more stable Hackage’, wasn’t really a thing when i first began this project, it may be worth looking into to avoid the dependency hell often associated with Haskell development.