Skip to main content
Martin Hähnel

How To Remove A Folder From The Generated Permalinks In Eleventy

When I moved to Eleventy with this blog, I made the "mistake" to organize my blogposts into a subdirectory called blog. In this way, I thought it would be easy to hide/reveal the ever-growing collection of subfolders and posts and the "root" of my contents folder would stay the same.[1]

An explanatory screenshot, showing the "blog" folder inside the content folder once open and then closed, with some accompanying text: If this wouldn't be inside "blog", listing the contents of the "content" folder would become very long over time instead, we just contain all blog posts within this "blog" folder which we can toggle open and "content" stays usable and clear.

The other main reason was that with a blog.11ydata.js file I could add a posts tag to all my blog posts and specify which layout template to use. It looks like this:

export default {
	tags: [
		"posts"
	],
	"layout": "layouts/post.njk",
};

However, what I didn't immediately realize was that the path inside the content folder would become part of the permalink. Looking at the site using the local development server didn't make that obvious, because the permalink to this file - before the applied fix, see below - would look like this locally:

http://localhost:8080/blog/2025/02/15/eleventy-change-permalinks/

But when I then published my posts the URL would look like this:

https://blog.martin-haehnel.de/blog/2025/02/15/eleventy-change-permalinks/

And this doubled blog in the URL bothered me. So I wanted to change it.

Thankfully Eleventy lets us change the permalink behavior of posts by using permalink in the front matter of a post. I have done this for alle the old posts that had a different permalink scheme, so anything that was written when this was still a hugo-based micro.blog has permalinks like this:

https://blog.martin-haehnel.de/2025/01/23/dailydogo.html

even though that file that is the source for this blog post lives under the path:

content/blog/2025/01/23/dailydogo.md

which normally lead to the permalink:

https://blog.martin-haehnel.de/blog/2025/01/23/dailydogo/

but we can overwrite this behavior by adding this to front matter of the post:

permalink: https://blog.martin-haehnel.de/2025/01/23/dailydogo.html

that's all that is needed to preserve the old permalinks.

If you try go to that URL you'll notice that the `.html` is missing from the URL. But the post is still found. My understanding is that this is done to make the URL "better". Read more in the Eleventy docs here.

Just as setting tags and layouts you can also manipulate the permalink scheme for all posts contained within a folder. Because you can't set a concrete permalink in this data file, you'll have to do it dynamically.

Quick Excursion To THe Data Cascade

But first lets talk shortly about what is called the "data cascade" within Eleventy: You can define metadata for your posts in more than one place. Two locations where you can define metadata we already talked about so far in this post are the following:

  1. in folders using 11ydata files
  2. in the front matter of posts themselves

There are actually a bunch more places where you could put stuff, but if we only talk about these two then anything you put into data files will be merged "over" by what you put in the front matter of posts. This means a couple of different things depending on what kind of data type we're talking about. For tags that means they are combined.

Example: This post has the tag "Blog" set and the data file specifies the "posts" tag. So this post will have both the "Blog" and the "posts" tag applied.[2] The data file also specifies a layout key for all blog posts. If I wanted, I could specify a specific layout for only one post by adding a layout key in the post instead.

If blog.11ydata.js looks like this:

export default {
	tags: [
		"posts"
	],
	"layout": "layouts/post.njk",
};

But the front matter of our post looks like this:

title: "How To Remove A Folder From The Generated Permalinks In Eleventy"
date: 2025-02-15T14:59:27+0200
layout: "layouts/post-special.njk"
tags:
  - "Blog"

Then the layout for this specific post will be layouts/post-special.njk, while all other posts will retain layouts/post.njk. So we can have the best of both worlds: We can define a default for a subset of our posts while also overwriting that default, if we want to. Cool.

Per default Eleventy creates permalinks by taking the path and file name starting from the content file. So this:

/blog/2025/02/15/eleventy-change-permalinks.md

will be turned into this:

/blog/2025/02/15/eleventy-change-permalinks/

We can overwrite this default behavior in our data file like so:

"permalink": "/blog/2025/02/15/eleventy-change-permalinks/foo/index.html"

In this way we end up with the following:

/blog/2025/02/15/eleventy-change-permalinks/foo/

You'll notice that the index.html part is not part of the URL that's another instance of making URLs more durable/"better". Read more in the Eleventy docs here.

In our case, we simply want to remove the blog from the generated permalink. This can be done like this:

"permalink": "2025/02/15/eleventy-change-permalinks/index.html"

The .slice(5) removes the first five characters from /blog/2025/02/15/eleventy-change-permalinks.md so the /blog part.

We end up with what we wanted all along:

/2025/02/15/eleventy-change-permalinks/

So what was this talk about the data cascade about? Well, I didn't have the time to immediately rectify the problem with the added blog in the URL and therefore have a handful of post that were published in this way and they should stay reachable that way. I also have almost 2k old posts that have different permalinks all together.

If you look at the URL of this post, you'll see that it looks how I want it to look. But my recent post about adding footnotes to Eleventy will have its permalink still including the blog part, because that's how it was published. And my old posts using their own permalink scheme are similarly unaffected. All thanks to hard coding the correct permalink values into the respective posts' front matter and otherwise using our new default permalink scheme.

All of these can exist at the same time, and we can still have a default for all of our posts that is different from whatever Eleventy is doing out of the box.[3] I love this flexibility.


  1. Technically the eleventy-base-blog which is the base... for this blog created that folder,but I ran with it without realizing the implications for permalinks. ↩︎

  2. There is no visible posts tag (e.g. on the tags page) , because this is purely a tag eleventy needs to paginate my posts. It is therefore filtered out when constructing the tags overview page and individual tag pages. ↩︎

  3. And only for these! None of my other pages need to adopt that new default, because it is scoped to this specific blog folder within my content folder. ↩︎