{ Back to projects }
Thumbnail

Here's Janus, my static blog generator

17-08-2026

Over the past months I've been building Janus, a SSG (Static Site Generator) that takes a directory of posts written in Markdown and the descriptions of "boards" (thematic collections of posts), then it "converts" the whole structure into a full HTML website with customizable styles, HTML templates for everything and aliases.

The website itself that you are reading is built on Janus.

You can read the full docs here on Github. It's easy to follow along and build your first website starting from the example blog.

I've made several attempts but I was never satisfied with the output and the codebase itself. The main difficulty was defining a blog structure that could get rid of multiple "chicken or the egg" and separation of responsibility problems:

  1. Posts properties and content had to be extracted before writing board HTMLs, because boards have a list of clickable previews of their linked posts.
  2. Boards needed to be initialized before posts, because post properties include the boards that the post belongs to.
  3. An HTML page can't be the result of a simple conversion of its respective MD file, because there need to be templates.
  4. Both MD posts and HTML templates need to have dynamically translatable keywords (aliases), but templates themselves need to have translatable property keywords of the current file in conversion (which could be a post or a board), for example "FIRST_BOARD".
  5. I had to weigh the pros and cons of boards BEING (special) posts vs. boards HAVING a post (their description) plus other posts.
  6. In additions to those, I had to find out how to make relative paths that never refer to the website root, as links could have broken otherwise if you were to move the website from a root directory to another.

That's how I solved these problems:

  1. Posts are objects with a dictionary of properties which can be extracted to write both the full post's HTML and its preview just by swapping templates.
  2. Separate data extraction and writing: initialize empty boards first, then write every post's HTML and at last write every board's HTML.
  3. Templates have a "CONTENT" keyword that gets replaced with the actual converted content.
  4. Alias translation is followed by another step to resolve post properties.
  5. Composition looked cleaner (boards HAVING a post).
  6. Just using pathlib wasn't enough, I had to make a structure in which every object knows a priori the paths of every linked page.

This version is the result of the fouth attempt and I'd say I'm pretty satisfied with how things turned out this time.