Track software versions for technical blog posts
Code in this blog post was written with versions: notionhq/client: 2.3.0, Nunjucks: 3.2.4, Node: 20.17.0

When I talk about blogging for developers, a recurring question is how to deal with code example rot. Programming languages, APIs and libraries evolve all the time and a code example written today for version 1.4 might not work anymore in 10 years when software is at version 18.12.
My answer has been: I don’t worry about it too much, I have dates for my posts and I hope people can figure it out. Second part of the answer has been: I’ve been thinking about tracking the versions in my blog post metadata but haven’t implemented it yet.
Following my rule of three is a pattern, I finally decided to start implementing this. I probably won’t be able to retroactively apply this to my old posts because it’s hard to find out which versions I had when I wrote something 6 years ago. But I’ll do my best to do it for any future blog posts that have code examples.
How I implemented it
My current blog CMS is
Notion. For my
blog post template, I added a new
multi-select field
and I add my versions in format of
software:version
.

Over time, I expect it to grow unwieldingly annoying but we’re not there yet so I’ll fix it if I ever get in trouble with managing it.
I use Eleventy for building my static site and I have custom tools to fetch blog posts from Notion and write them as Nunjucks files that then get built into the static site.
To fetch my posts from Notion API, I use their official SDK and the multi-select field is stored there as an object that looks like this:
{
"id": "post-id",
"type": "multi_select",
"multi_select": [
{ "id": "entry-id", "name": "Python:3.13", "color": "red" }
]
}
I then convert that to something I can use easier:
// properties is variable that holds all the metadata for the post from Notion
const versions = properties.versions.multi_select.map(multiselect => {
const [software, version] = multiselect.name.split(':');
return { software, version };
})
And then write it to my post’s frontmatter:
`- ${versions.map((v) => `${v.software}: ${v.version}`).join("\n - ")}`
When I run it for this blog post, I end up with a YAML frontmatter structure like this:
versions:
- notionhq/client: 2.3.0
- Nunjucks: 3.2.4
- Node: 20.17.0
In my blog post template, I then check if versions are listed and add them after my date and category information:
{% if versions %}
<div class="software-versions">
<p>Code in this blog post was written with versions:
{% for entry in versions %}
{% for software, version in entry %}
<span>{{software}}: {{version}}</span>
{% endfor %}
{% if not loop.last %}
,
{% endif %}
{% endfor %}
</p>
</div>
{% endif %}
loop.last is a nice way in Nunjucks templates to check if we’re on the last iteration of the loop or not. In my case, I add a comma after each entry as long as we’re not on the last iteration.
On a blog post, it then looks like this

I will iterate over the design further but right now, the first version is published and I think it’s already an improvement compared to what I had before. What I like about my custom tooling is that I can write and showcase the information in any format I want making it very flexible.
If you have thought about this problem and solved it with something similar (or something completely different), I’d love to hear your thoughts and experiences!
If something above resonated with you, let's start a discussion about it! Email me at juhamattisantala at gmail dot com and share your thoughts. In 2025, I want to have more deeper discussions with people from around the world and I'd love if you'd be part of that.