Smart Static Sites

with Hakyll

-Eric Rasmussen

Back to the 90's

Eric's home page!!!

Maybe not those 90's

But static sites are coming back in style

What are static site generators?

  • think of them as build tools
  • turn any input into html
  • rebuild when content changes

But really... why?

  • minimalism
  • reduce security concerns
  • version control
  • it's fun

Text format of your choice

  • markdown
  • ReSTructured text
  • LaTeX
  • MediaWiki

Syntax highlighting

match ("about.markdown" .||. "commands.markdown") $ do
    route   $ setExtension "html"
    compile $ pandocCompiler
        >>= applyBase
        >>= relativizeUrls

"What's hard to ignore about all these platforms is that, your dad will never blog like this."

-Mike Bayer (author of SQLAlchemy)

Why not?

  • takes time to configure
  • the wild wild west
  • geek factor


Rules-Based EDSL

configuration via code

match ("images/*" .||. "js/**") $ do
  route   idRoute
  compile copyFileCompiler

match ("css/*" .||. "css/icons/*" .||. "foundation/*") $ do
    route $ setExtension "css"
    compile sassCompiler


  • dependency resolution
  • simple file metadata
  • snapshots (during build)

Hakyll built-ins

  • tags and tag cloud rendering
  • rss/atom feed generation
  • code syntax highlighting
  • templating

Example: render posts

match "posts/*" $ do
    route   $ setExtension "html"
    compile $ pandocCompiler
        >>= saveSnapshot "content"
        >>= loadAndApplyTemplate "templates/post.html" postCtx
        >>= loadAndApplyTemplate "templates/base.html" baseCtx
        >>= relativizeUrls

Example: create an atom feed

create ["atom.xml"] $ do
    route idRoute
    compile $ do
        loadAllSnapshots "posts/*" "content"
            >>= fmap (take 10) . recentFirst
            >>= renderAtom (feedConfiguration "All posts") feedCtx

Example: create a context

defaultPostCtx :: Tags -> Context String
defaultPostCtx tags = mconcat
  [ dateField "date" "%B %e, %Y"
  , tagsField "tags" tags
  , defaultContext

Example: sass/scss compiler

sassCompiler :: Compiler (Item String)
sassCompiler =
    >>= withItemBody (unixFilter "sass" ["-s", "--scss"])
    >>= return . fmap compressCss


  • Swiss-army knife of markup
  • Can parse several markdown/markup formats
  • Can output to html, tex, pdf, and other formats

Go dynamic with javascript

  • visual effects
  • indexed search (sphinx)
  • comments (Disqus, Branch)
  • live feeds (twitter,

The Haskell Connection

  • You don't need to know Haskell for Hakyll
  • But know that Haskell is awesome
  • Modern type systems are expressive and productive
  • Beginner friendly community


Haskell is... too awesome?

"a monad is a monoid in the category of endofunctors, what's the problem?"

For complex sites

  • Haskell knowledge likely required
  • DSLs can be hard to hack on
  • but there are open source examples

Where to begin

The Hakyll tutorials are a great starting point

But if you already have a favorite language, try:

  • pelican (python)
  • jekyll (ruby)
  • nanoc (ruby)
  • middleman (ruby)
  • high_voltage (ruby)

(ruby devs like DSLs)

(but you can find examples in most languages)

A word of caution

The good news: typically no proprietary format or DB, but...

  • Static site generators come and go
  • Prepare for breaking changes/tinkering
  • No security patches! (good thing)


  • it's plain html and assets
  • so you can deploy just about anywhere
  • rsync -zrv mysite/ [email protected]:~/mysite/
  • GitHub Pages (

CSS for non-designers

  • Don't do it
  • Just... don't

The easy way

  • Use twitter bootstrap
  • Or zurb foundation
  • Learn grid systems and responsive classes


Use grid layouts to design big


Design small at the same time


  • variables -- $blue: #3bbfce;
  • functions -- darken($blue, 9%);
  • like coding, but not
  • reduces CSS madness boilerplate
  • compile with your build process

Choose your own adventure


  • haskell
  • hakyll
  • javascript + services
  • responsive design