Skip to content

Migrating my site from NextJS to Eleventy

I recently migrated my website from NextJS to Eleventy.

Dec 17, 2023
Dec 17, 2023
Reading time
4 min read

Previous Stack


Previously, this website was built with NextJS, a React Framework. The content of my website is completely static, so I used the static export feature, which pre-renders the whole website during build. No server-side rendering and no need for a node server at all, just static files.

The website worked without JavaScript as a multipage app but turned into an SPA when JavaScript was enabled. Therefore, a lot of JS and other content was downloaded and executed. Given that my website had nearly zero interactive elements, this was a lot of overhead. Migrating to the App Router and React Server Components would probably help to reduce the bundle size.

Vanilla Extract

For styling, I used Vanilla Extract, a CSS-in-JS library that extracts the styling during build, so there is no additional runtime overhead. Thanks to it's type-safe API, it provides a great developer experience.


My blog posts are stored in plain Markdown files with front matter. I used Remark / Rehype to convert the posts into HTML but later on switched to Markdoc which is much easier to use and customize.

New Stack


I now migrated my website to Eleventy, a static site generator, which I already use for, and I really like it. For the project structure I got inspired by Lene Saile's Organizing the Eleventy config file article.

My blog posts are still plain markdown files and I use custom collections to render the list of posts. Thanks to layout chaining I can have a base layout and a separate layout for my blog posts based on the base layout.

The list of my projects are stored in a JSON file using the Eleventy data cascade feature.


For other projects, like Eleventy Notes, I used Nunjuck templates. For my website I now use WebC. WebC provides a framework-independent standalone HTML serializer for generating markup for web components.

With WebC you can create components like this:

<script webc:setup>
  const today = new Date().toLocaleDateString();

<div class="info">Built on <span @text="today"></span></div>

<style webc:scoped>
  .info {
    color: lightgray;

The script part will be executed during build to set up the component and does not generate any runtime JavaScript. The result is just HTML and a separate CSS file containing the scoped styles for this (and any other) component.


In addition to scoped styles in WebC components using CSS, I also have some global styles using SCSS files. Compiling them to CSS is done via eleventy-sass plugin in combination with eleventy-plugin-rev to create hashed files.


Parsing markdown comes for free with Eleventy. I tried to integrate Markdoc, but it didn't go so well and doesn't make sense anyway, as the setup is quite different. I now rely on the default markdown library markdown-it shipped with Eleventy, with some additional plugins and customization.

RSS Feed

For my RSS feed, I use the official RSS plugin from Eleventy. The feed now includes not just the description, as it did before, but also the actual content, thanks to the plugin that automatically converts urls (images, links, ...) to absolute urls.


The good parts

I'm pretty happy with the migration to Eleventy. It was easy to migrate and provides good developer experience.

The performance of the website has highly improved thanks to Eleventy:

  • Transferred Resource size reduced by 40%
  • Resource size reduced by 65%
  • Number of requests reduced by 70%
  • PageSpeed Insights Performance went up from 90% to 100%
  • Build Time reduced by 50%

The bad parts

Nothing can beat a React Components + TypeScript setup in terms of developer experience. I definitely miss TypeScript but overall the developer experience is still pretty good. I would not like to switch back.

WebC is in its early stage and did not even reach version 1. Google doesn't seem to know the term "Webc" at all, the documentation could be improved and there are some bugs, for example:

  • Dev Server needs to be restarted all the time because changes are not reflected (existing issue #2903, fixed but not released yet)
  • Content of pages cannot be accessed, I had to remove the reading time on the posts list (reported #92).
  • CSS scoping is not working for some selectors, like :host + :host (reported #198)

But as WebC gets more stable, it provides a pretty good developer experience and is much more convenient to use than Nunjuck.