Building My Own Static Blog Generator
How I built a small static blog generator using Node.js and Markdown.
Building My Own Static Blog Generator
A portfolio is supposed to show what you can build.
So I wanted mine to include something I could actually build myself.
Rather than connecting a database or introducing a server-side application just to publish a few articles, I chose to build a small static blog generator from scratch.
The idea is simple:
Write posts in Markdown. Run one command. Get a complete static website.
That way, the blog becomes part of the portfolio itself, without the need to maintain a separate system just to publish articles.
Why Build One?
There are plenty of excellent blogging platforms available, so building another one might seem unnecessary. But beyond having the blog as part of the portfolio, developing the system gave me an opportunity to experiment with file handling, Markdown parsing, HTML generation, templates, and the small details that are usually hidden behind a CMS.
More importantly, I wanted to understand what was actually happening under the hood.
A traditional blog might look something like this:
Browser
│
▼
Web Server
│
├── Application
│ │
│ ▼
│ Database
│
▼
Generated HTML
This blog is considerably simpler:
Markdown
│
▼
Node.js Generator
│
├── Parse front matter
├── Convert Markdown
├── Apply templates
└── Generate HTML
│
▼
Static Website
Once the files have been generated, the server doesn't need to do any of that work.
Why Static HTML?
Static websites have a lot going for them: they are fast, simple to deploy, easy to maintain, and require far fewer moving parts than a traditional dynamic application.
Speed
There is no application running every time someone opens an article. The server can simply return an already-generated HTML file.
Simplicity
There is no database to configure, migrate, back up, or maintain, as the source of truth is just a collection of Markdown files.
Deployment
The generated files can be deployed almost anywhere that can serve HTML. That makes the deployment process extremely simple:
Build → Upload → Done
Reliability
Fewer moving parts generally means fewer things that can break. As long as the generator works and the generated files are correct, the website doesn't need much else to run.
JavaScript is only required when generating the site, so the blog remains fully usable even if a visitor has disabled JavaScript in their browser.
Security
There is no public database and no server-side blog application handling requests. The attack surface is therefore much smaller than that of a typical dynamic application.
The Source Files
Each article lives in its own Markdown file.
For example:
posts/
├── static-blog-generator.md
├── another-project.md
└── things-i-learned.md
Each file starts with metadata describing the post:
---
title: "Title of the Post"
date: "Current date"
description: "Brief description of the post."
slug: "url-for-the-post"
tags:
- Tag1
- Tag2
---
Everything after the metadata is simply Markdown, so writing a new article is as easy as creating a new file.
Templates
One of the most useful parts of the generator is its template system.
The blog index uses a simple template:
<main class="blog-page">
<section class="blog-hero">
<div class="blog-container">
<h1>Blog</h1>
<div class="blog-title-line"></div>
<p>Thoughts, projects and things I've learned.</p>
</div>
</section>
<section class="blog-posts">
<div class="blog-container">
<div class="blog-post-grid">
{{POSTS}}
</div>
</div>
</section>
</main>
During the build process, the generator replaces {{POSTS}} with the cards generated from the available posts.
Individual articles use a separate template:
<main class="blog-page">
<article class="blog-article">
<div class="blog-container">
<a href="/blog/" class="blog-back">
← Back to blog
</a>
<div class="blog-article-card">
<header class="blog-article-header">
<h1>{{TITLE}}</h1>
<div class="blog-title-line"></div>
<div class="blog-article-meta">
<time datetime="{{DATE_ISO}}">
{{DATE}}
</time>
{{TAGS}}
</div>
<p class="blog-article-description">
{{DESCRIPTION}}
</p>
</header>
<div class="blog-content">
{{CONTENT}}
</div>
</div>
</div>
</article>
</main>
This keeps the content separate from the presentation.
The Markdown file doesn't need to know anything about CSS, layouts, or HTML structure. It only contains the content and metadata, while the templates determine how that content is presented.
The Build Process
When running:
npm run build
the generator goes through a series of steps.
First, it finds the Markdown files.
Then it reads their metadata and content, converts the Markdown into HTML, and inserts the result into my blog templates.
The final result might look something like:
dist/
├── blog/
│ ├── index.html
│ └── static-blog-generator/
│ └── index.html
├── css/
│ └── style.css
└── index.html
The browser never needs to know that Markdown was involved, as it only sees the generated HTML. Also, by using recursive index files, the URLs are clean and simple:
marcosistoocommon.com/blog/static-blog-generator/
What I Learned
When I started this project, the main question was how to make a blog work with the limited resources available on this server. Building the tool myself was already part of the plan, but it wasn't clear whether a full backend application would be practical with the available resources.
While researching possible solutions, I came across static site generators and realized that this approach was a good fit for my needs. Markdown was another new area for me, which made it a good opportunity to learn something new while keeping the writing process simple.
The project also provided an opportunity to learn more about managing files through code and using predefined templates to generate files automatically.
What's Next?
Although I am satisfied with the current version, there are still a few features I would like to add in the future:
- Implement KPIs for the posts
- Add pagination to the blog index
- Add image support to the generator
- Add a search feature
None of these are a priority for now, though. The current version is already functional and meets my needs. As I learn more and my needs evolve, I can continue expanding the generator and adding new features.
A Small System With a Simple Idea
An existing blogging platform would probably have saved me some time. But honestly, that wasn't really the point. The goal was to have a place on my portfolio where I could write about the things I'm building, and building the blog itself seemed like a good first topic.
There is also something satisfying about having full control over the system. Changes to the way posts are generated can be made directly in the generator. New features can be added whenever they become useful, and the design can be changed without having to work around someone else's platform.
For now, this is enough.
The generator will probably break a few times. There will be features that seemed like a good idea at first but eventually turn out to be unnecessary, and the design will probably change more than once. That's part of the process.
At least now there is somewhere to write about it.