Our new website - from Hexo to 11ty

Ingmar Jager
Ingmar Jager
January 13, 2026
Lees in het Nederlands
Website Development

It's finally here: our website has received a major update. After running on Hexo for years, it was time for something new. We chose Eleventy (11ty) as our static site generator, combined with Tailwind CSS for styling.

Why the switch?

Our old Hexo website served us well, but there were a few points that bothered us:

  • Outdated dependencies - Node packages that were no longer maintained
  • Limited flexibility - Layout adjustments were cumbersome
  • Build performance - The build became increasingly slow as the site grew

The pain points in detail

The biggest problem was maintenance burden. Every time we ran npm install, we got a long list of security warnings. Packages that hadn't been updated for years, dependencies of dependencies causing conflicts.

"The best code is code you don't have to maintain."

This wisdom resonated more and more as we spent more time updating tooling than writing content.

What we were looking for

We compiled a list of requirements:

  1. Modern tooling with active community
  2. Simple architecture without too much abstraction
  3. Good developer experience with fast builds
  4. Flexibility in templating and styling

The technical stack

After evaluating various options, we settled on this combination:

Component Choice Why
SSG Eleventy 3.x Simplicity, speed, flexibility
Styling Tailwind CSS 4 Utility-first, no CSS bloat
Templating Nunjucks Powerful, good 11ty integration
Hosting Netlify Automatic deploys, CDN

Eleventy: the core

11ty is refreshingly simple. No magical configuration, no hidden conventions. You give it files, it makes HTML from them.

Configuration

The entire configuration fits in one file:

export default function (eleventyConfig) {
  // Collections for blog posts
  eleventyConfig.addCollection("blogNL", function(api) {
    return api.getFilteredByTag("blogNL")
      .sort((a, b) => b.date - a.date);
  });

  // Passthrough for images
  eleventyConfig.addPassthroughCopy('src/assets/img');

  return {
    dir: { input: 'src', output: 'dist' }
  };
}

Filters

Custom filters make life easier:

// Date formatting per language
eleventyConfig.addFilter("localDate", function(date, lang) {
  const locale = lang === 'nl' ? 'nl-NL' : 'en-US';
  return new Date(date).toLocaleDateString(locale, {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
});

Tailwind CSS 4

The latest version of Tailwind brings significant improvements:

New features

  • CSS-first configuration - No more tailwind.config.js needed
  • Native CSS nesting - Cleaner syntax
  • Improved performance - Faster builds

Example: a button component

<button class="
  bg-blue-600 hover:bg-blue-700
  text-white font-semibold
  px-6 py-3 rounded-lg
  transition-colors duration-200
  shadow-lg hover:shadow-xl
">
  Submit
</button>

The result: consistent design without growing CSS files.

Content management

Directory structure

We chose an intuitive folder structure:

src/
├── blog/
│   ├── blog.json           # Defaults for NL posts
│   ├── 2026-01-13-post/
│   │   ├── index.md        # Content
│   │   └── banner.jpg      # Images
│   └── legacy/
│       └── old-post/
│           └── index.md
├── en/
│   └── blog/
│       ├── blog.json       # Defaults for EN posts
│       └── 2026-01-13-post/
│           └── index.md
└── _includes/
    ├── post.njk
    └── blog-card.njk

Co-located images

A handy feature: images are stored in the same folder as the blog post.

Advantages

  • Overview - Everything together
  • Deletion - Delete the folder, done
  • Moving - Drag & drop the entire folder

Implementation

In the frontmatter:

banner: banner.jpg  # Relative path

In the template:

<img src="[page.url][banner]" alt="[title]">

(With Nunjucks variables between double curly braces)

Bilingual setup

URL structure

Language Blog index Post URL
Dutch /blog/ /blog/2026-01-13-post/
English /en/blog/ /en/blog/2026-01-13-post/

Linking translations

Via the translationKey in frontmatter:

# Dutch version
translationKey: my-post-2026
lang: nl

# English version
translationKey: my-post-2026
lang: en

The template automatically shows a link to the translation when available.

What we learned

Do's

  1. Start simple - Add features when needed
  2. Preserve URLs - Important for SEO and bookmarks
  3. Document choices - Your future self will thank you

Don'ts

  1. Don't over-engineer - YAGNI (You Aren't Gonna Need It)
  2. Don't copy boilerplate - Understand what you're adding
  3. Don't forget accessibility - Semantic HTML, alt texts

Technical learnings

Performance optimization

  • Lazy loading for images below the fold
  • CSS purging for minimal bundle size
  • Setting cache headers correctly

SEO considerations

  • Canonical URLs for translations
  • Structured data for blog posts
  • Automatically generate sitemap

Next steps

The foundation is in place, but there's always more to do:

Short term

  • [ ] Implement RSS feed
  • [ ] Open Graph meta tags
  • [ ] Style 404 page

Long term

  • [ ] Search functionality
  • [ ] Related posts
  • [ ] Reading time indicator

Conclusion

The migration from Hexo to 11ty was worth it. We now have a faster, more maintainable website with modern tooling. The learning curve was minimal and the developer experience is excellent.

Have questions about our approach or want to discuss your own website? Get in touch!