The Curious Case of Missing Post Tags in Eleventy

March 25, 2021    

I've recently started using Eleventy for this website. Like most people who are getting started, I found an example site that did most of what I wanted and started tweaking it to my needs. One thing I saw others do that I wasn't able to do (yet) was automatically tag all files in a directory to indicate that they are posts.

A quick background about collections

In Eleventy you will eventually work with collections, which are what they say on the tin — collections of items, be it blog posts, tags, or whatever. In my case, I have a posts directory that contains all the markdown files representing posts for the blog. Eleventy is smart enough to aggregate everything I've tagged with "posts" and then I can call for those when showing a post list.

The most basic setup for tags

Here's a very basic example:

File:src/posts/bark-of-the-aardvark.md
---
title: The Bark of the Aardvark
tags:
- posts
---

Since I tagged this with "posts", when I ask for the collection called "posts" it'll come along for the ride. All is good, right?

Level up — directory specific data files

I'm a developer, and therefore am inherently lazy. I want to do the least possible work to achieve as good a result as possible. I don't want to have to tag every blog post with "posts" because it takes time (albeit a miniscule amount), but more importantly, I have to remember to do it. What kind of debugging hell am I going to get myself in to the minute I forget that tag? Will my brain connect the dots that I forgot the critically important "posts" tag?

This is where directory specific data files come in handy. Since all of my post files are in a single directory (boringly called "posts"), I can add a directory data file posts.json to that directory and everything in it will assume whatever I put in the file. It's not a coincidence that the directory and the file name match — they don't have to, but for the sake of simplicity, I set it up this way. More on your options later...

Another quick example to show what that would look like:

File:src/posts/posts.json
{
"tags": "posts"
}

With this file in place, everything in the posts directory automatically gets the tag "posts", which means I can save 0.25 seconds per blog post by not having to type out the word "posts" in the tags section. This is the epitome of optimization! /s

Here's where you can get got

The first time I tried this, I didn't understand how data cascade works in Eleventy. I thought that since I used the directory specific file that the tag would always be added. Well, it was, until I started tagging posts with other tags, like this:

File:src/posts/bark-of-the-aardvark.md
---
title: The Bark of the Aardvark
tags:
- animals
- stories
---

Notice that I left out "posts" because it should be brought in from the JSON file. Sweet! BUT... What I was seeing was that The Bark of the Aardvark was no longer in my post list. It took me a second of reading the docs to realize that local data keys override global data. In other words, because I added the tags "animals" and "stories" in my post, the "posts" tag gained from the directory data file was lost.

The solution

Once I had the problem pinned down, the solution was incredibly simple. What is needed is to add the data deep merge setting in .eleventy.js. As per the documentation, this will likely become the default and this whole article will be moot. In the interim, hopefully someone finds this useful.