Flatten Nuxt Content Routes

I wanted to organize my blog content into several folders:

  • Articles: content/articles/
  • Newsletters: content/newsletters/

By default though, Nuxt Content would set up these routes to include those prefixes. But I want all of my routes to be at the root level:

  • Articles: michaelnthiessen.com/my-latest-article
  • Newsletters: michaelnthiessen.com/most-recent-newsletter

We can do this manually for each Markdown file by overriding the _path property through it's frontmatter:

---
title: My Latest Article
date: today
_path: "/my-latest-article"
---

This is extremely tedious, error-prone, and generally annoying.

Luckily, we can write a simple Nitro plugin that will do this transform automatically.

Create a content.ts file in server/plugins/:

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('content:file:afterParse', (file) => {
for (const prefix of ['/articles', '/newsletters']) {
if (file._path.startsWith(prefix)) {
// Keep the prefix so we can query based on it still
file._original_dir = prefix;
// Remove prefix from path
file._path = file._path.replace(prefix, '');
}
}
});
});

Nitro is the server that Nuxt uses internally. We can hook into it's processing pipeline and do a bit of tweaking.

However, doing this breaks queryContent calls if we're filtering based on the path, since queryContent is looking at the _path property we've just modified. This is why we want to keep that original directory around.

We can modify our queryContent calls to filter on this new _original_dir property:

// Before
queryContent('/articles')
// After
queryContent()
.where({
_original_dir: { $eq: '/articles' },
});

Pro tip: use nuxi clean to force Nuxt Content to re-fetch and re-transform all of your content.