// Blog
// Development

Why I built my own static site generator

There are dozens of static site generators – yet I wrote my own, Nera. A look at the reasons and at how it works

Screenshot of the project website nera.js.org

Anyone who wants to build a static website today is spoilt for choice: Hugo, Eleventy, Astro, Jekyll and many more. Writing yet another static site generator looks like an exercise in stubbornness at first glance. I did it anyway. The result is called Nera, it's open source – and this website is built with it, too. In this article I explain what Nera does, how it's structured and why I built it.

Why static at all?

Before we get to Nera, a quick word on the basic idea. A static site generator creates finished HTML files from content and templates – once, when the site is built. After that, the server only holds files. That has tangible advantages:

  • Speed: The server delivers finished files instead of assembling pages from a database on every request.
  • Security: Without a database, login area and server-side scripts, there is much less attack surface. There's no admin password to guess and no plugin quietly ageing without patches.
  • Little maintenance: No database updates, no security updates for a CMS in operation.
  • Cheap hosting: Static files run on practically any web space.
  • Versioning: Content and code live together in Git. Every change is traceable and reversible.

Of course this doesn't suit every project. If several people without technical knowledge regularly maintain content, a CMS like Statamic or WordPress is often the better choice. My references include examples of that too. For websites I maintain myself, for project sites and documentation, however, the static approach is ideal.

Why my own?

It started with a very concrete problem. I had built a static website for an inn – plain HTML, because the content hardly ever changed. Then the site was supposed to show events. Editing the HTML by hand every time was annoying and not an option in the long run.

So I looked for the simplest possible solution. Everything I found came with far too much overhead for such a small task. That's how the first version of Nera came about – back then it didn't even have a version number. With every project, this small tool grew a little more.

The basic idea has stayed the same: the core of Nera should do only one thing, namely turn Markdown files into static HTML files. Everything else is optional.

A second reason is more general and applies to many tools: if you built a tool yourself, you know every corner of it. When something on one of my sites doesn't work as expected, I don't have to search through other people's forums – I know where to look. And I can build exactly what I want. One example is the contact form: I like it when a contact request is simply sent as an email. So it was natural to write my own plugin for it. For me, that has several advantages:

  • No processing on the server: The web server only delivers the page. There's no need for a script that receives and forwards the request.
  • No stored data: The message doesn't end up in a database anywhere; it goes straight from the visitor's email program to me.
  • No external service: No form provider that data is passed to, and no additional data processing agreement.
  • A clear project: The form fields live in a short YAML file, and I write the content in Markdown like the rest of the site – which I like a lot because it's so clear. Especially for small and medium-sized websites, everything stays simple and manageable.

How Nera works

The principle is deliberately simple: Markdown in, HTML out.

Content is written as Markdown files in the pages/ folder. At the top of each file there is metadata in YAML format, the so-called front matter. A page looks like this, for example:

---
title: Imprint
layout: pages/default.pug
lang: en
---
This is the actual content, written in plain **Markdown**.

The layout entry determines which template the page is rendered with. Pages without a layout aren't output as their own HTML file – which can be used to store reusable text snippets.

The templates are written in Pug, a compact template language that does without closing HTML tags. The global configuration lives in config/app.yaml: the website's name, translations, the active design and options such as asset hashing.

When building, Nera goes through four steps: load the configuration, read and convert the Markdown files, apply plugins and finally write the HTML files to the public/ folder. That folder is then simply uploaded to the web server.

Plugins instead of feature bloat

The core of Nera deliberately does little. Everything else comes via plugins, each published separately on npm as @nera-static/plugin-*. This website uses, for example:

  • navigation for the main and footer navigation
  • tags for tags and the overview page per tag
  • popular-content for the teaser lists of services, references and blog posts
  • stacks for reusable content blocks
  • canonical-links for canonical and hreflang tags on multilingual sites
  • link-attributes for attributes on external links
  • contact-form for a contact form without server-side processing that opens the email program with a pre-filled message on submit

Each project only includes what it needs. Every plugin is configured via its own YAML file in the config/ folder.

One package, one command line

With the current version, a Nera project is deliberately lean: a new project starts with exactly one dependency, the package @nera-static/nera, which brings the command line with it. Plugins are only added when you need them. A project is created with one command:

npx @nera-static/nera new my-site
cd my-site
npm run dev

After that, the commands nera dev (build, serve locally and rebuild on changes), nera build, nera validate (checks layouts, includes and YAML before publishing) and nera update are available. Older Nera projects can be switched to the new model with nera update --migrate – that's how this website moved, too.

Designs can be included as themes. This website, for example, has two: the current "Technical Grid" design and the previous one, and I can switch between them with one line in config/app.yaml.

What Nera isn't – and what's coming

Nera is a project I develop alongside my work. It doesn't have a huge community or an ecosystem with hundreds of extensions. If you need that, you're better served by established generators. But if you're looking for a small, manageable generator that you can understand completely in a short time, you're very welcome to try it.

I'm very happy with the current version, and I don't expect any fundamental changes. On the contrary: the new structure with one package and one command line makes it easier to add new features. I'm already working on one: in future, Nera websites should also be editable through a graphical interface in the browser. That makes the static approach interesting for projects where a classic CMS is still the better choice today.

Besides this website and nera.js.org, Nera is used, for example, by a craft business and an insurance advisor. I'd be really happy if Nera became better known, because I believe its minimalist approach is exactly what sets it apart from other generators. New ideas, bug reports and contributors are always welcome – the easiest way is an issue on GitHub.

Conclusion

Building your own static site generator isn't a decision I'd recommend to everyone. For me it was worth it: I have a tool that does exactly what I need and that I understand completely. The basic idea of static websites – fast, secure, low-maintenance – applies regardless of which tool is used to build them.

The source code is on GitHub, the documentation on nera.js.org. And if you're wondering whether a static website suits your project, feel free to get in touch.

Yours, Michael Becker