Eleventy vs. Next.js for static site generation

mangelosanto

Matt Angelosanto

Posted on December 14, 2023

Eleventy vs. Next.js for static site generation

Written by Nelson Michael✏️

Static websites are easy to build and maintain and generally deliver faster performance from the user's perspective compared to dynamic websites. The content is pre-built, requiring minimal backend processing and less complex caching.

In this article, we’ll evaluate and compare two popular static site generators: Eleventy and Next.js. These tools offer a variety of advantages in terms of performance, developer experience, scalability, and ecosystem, making them suitable for different scenarios.

TL;DR

  • Opt for Eleventy if your priorities include simplicity, pure static site generation, and a streamlined approach. It is fast and powerful because it does not require the loading of a client-side JavaScript bundle to serve content
  • Choose Next.js if you require advanced functionalities, server-side rendering, dynamic routing, and access to a vast ecosystem for intricate projects

What’s a static site?

A static site is made up of pre-compiled content, including HTML, CSS, assets, and other elements. These components are assembled before being uploaded to a web hosting platform. In contrast, dynamic websites create these elements in real time by querying a database or fetching content from client-side APIs.

A static site generation (SSG) tool is software that’s used to create static websites. It serves as an environment and build processor to compile your content into static HTML.

Here’s an illustration showing how SSG tools work: Static Site Generator Flow

The simplicity of a static website offers several benefits. First, it’s the easiest type of site to create from scratch and maintain, making it a solid choice if you need to launch a basic site quickly and cost effectively. Any developer with knowledge of HTML and CSS can easily code a decent static site without significant effort or expense.

Static websites tend to deliver faster performance compared to dynamic websites. Since the webpages are prebuilt, the server only has to retrieve the requested files and deliver them to the client. Static websites are also simpler to cache due to their consistent content.

Getting to know Eleventy

Eleventy is a fast and powerful SSG that really shines when it comes to pure static site generation because it does not require the loading of a client-side JavaScript bundle in order to serve content.

Eleventy is “zero-config” by default. If you make no modifications, it will automatically process all the files in your project's root directory, perform a build operation, and then save the resulting files to a _site directory.

It also has flexible configuration options, enabling you to customize your build process, watch for changes in certain file types, and manipulate content with filters and shortcodes. Your custom Eleventy configuration goes in a .eleventy.js file at the root of your project.

As an example of the level of customization that’s available, you could opt to change the default input and output directories of your project from the root and _site, respectively, to something else. Many people prefer to use src for the input directory and public for the output directory.

Eleventy offers a great developer experience. For example, it includes an inbuilt --serve flag that uses Browsersync to enable serving the site locally and with hot reload upon file changes. This is a huge convenience. Another distinctive feature is its capability to choose from and combine up to ten different templating languages, such as JavaScript, Haml, Pug, Liquid, and more.

Getting to know Next.js

Next.js is a robust and versatile framework for web development, excelling in various scenarios. It seamlessly handles both server-rendered and statically exported React applications and websites. The framework not only streamlines the essential tooling and configuration for React, but also enriches the developer experience by providing additional structure, features, and performance optimizations.

With Next.js, you can choose between two primary rendering methods:

  1. Server-side rendering (SSR): Pages are pre-rendered on the server side before being sent to the client, resulting in efficient and search engine-friendly content delivery
  2. Static site generation: Pages are pre-rendered at build time, making it possible to serve entire websites as static assets and offering excellent performance and scalability benefits

When using an SSG is used in conjunction with Next.js, pages are pre-rendered during compilation. In this scenario, users don't experience loading times in their browsers as the pages are readily rendered.

For data retrieval, Next.js offers three distinct functions:

  1. getStaticProps: Pages are pre-rendered during the build process
  2. getServerSideProps: Pages are pre-rendered during runtime
  3. getStaticPaths: This function generates a list of pages slated for pre-rendering during the build phase

Comparing Eleventy and Next.js

Here’s a comparison of the overall performance, developer experience, scalability, and ecosystem for Eleventy and Next.js:

Eleventy Next.js
First release 2018 2016
Github stars 15k+ 114k+
Templating language JavaScript, HTML, Markdown, Liquid, Nunjucks, Handlebars, Mustache, EJS, Haml, Pug, WebC JSX
Plugins Yes Yes
Image optimization Yes Yes
Environmental variables Yes Yes
Content security policy Custom HTTP headers rules Via next-secure-headers
Code splitting Yes, but you have to set it up manually Yes

Example project

To better understand how Eleventy and Next.js function, let's create a simple blog project. We’ll document the performance of both tools, as well as other aspects of the development process.

Most developers have a general understanding of what a blog is, but it's important to note that blogs can have unique characteristics. In this guide, we will implement the following features:

  • A homepage that showcases our most recent blog articles, starting with the newest content
  • A page dedicated to displaying individual blog posts. This page will show the post's title, publication date, and full content

Building a simple blog with Eleventy

First, let’s define the post structure for our sample blog. To keep things simple, we’ll have a maximum of five blog posts. The markdown files for each of the blog posts will reside in a posts folder.

By default, Eleventy will generate a permalink each time we create a new file. The post URLs will look something like this: https://blog/posts/post1.md.

Setup

In general, an Eleventy project operates within a self-contained environment, where all the files and resources are organized within a primary folder. This arrangement allows you to conveniently execute the eleventy command from the command line while working within the current directory.

For our sample project, we’ll adopt a similar structure with a slight variation. We’ll introduce a single root directory that will house any necessary configuration for the blog; the actual content and additional templates will reside in a subdirectory beneath it.

To initiate setup, create a new root directory, which you may name eleventy-blog or something else of your choosing. Navigate to this directory from the command line and then initialize a new Node-related project using the following command:

npm init -y
Enter fullscreen mode Exit fullscreen mode

Next, install Eleventy as a dependency:

npm install --save-dev @11ty/eleventy 
Enter fullscreen mode Exit fullscreen mode

Inside of the root directory, make a blog directory and an .eleventy.js file that for now only contains the following:

module.exports = eleventyConfig => {
        return {
                dir: {
                        input: 'blog'
                }
        }
};
Enter fullscreen mode Exit fullscreen mode

Inside the blog directory, create an index.liquid file. This will be our blog’s homepage. Eleventy provides a number of options when selecting a template engine. For this project, we’ll use Liquid.

Add the following code to the index.liquid file:

<h1>Blog Posts</h1>

<ul>
{% for post in collections.post reversed %}
  {% if forloop.index <= 10 %}
      <a href="{{post.url}}" style="text-decoration: none; color: #010101; font-size: 20px">
          <p>
            {{ post.data.title }}
          </p>
      </a>
  {% endif %}
{% endfor %}
</ul>
Enter fullscreen mode Exit fullscreen mode

Content creation

Now let’s start writing the blog posts. Inside the blog directory create a posts directory to house the markdown files for each blog post on the blog. Next, create five blogs and add content, following this format:

---
title: Post Title
date: 2022-01-02
tags: post
---

All content goes here
Enter fullscreen mode Exit fullscreen mode

Earlier, we defined the front matter data, which is just the title, date, and tags of the blog. Ensure everything is working by running npx @11ty/eleventy at the CLI. You should get output like this: Eleventy Blog Output Since we’re still developing and will likely make many more changes, let’s spin up an eleventy server so that we can iterate faster:

npx @11ty/eleventy --serve
Enter fullscreen mode Exit fullscreen mode

Running this command fires up Eleventy in "server" mode, allowing you to open the site in your web browser, typically on port 8080.

When it comes to setting up an Eleventy blog, the heavy lifting mainly revolves around the initial configuration, layout, and related groundwork. Once that's squared away, you're pretty much set to dive into creating and publishing your content.

We were able to get our Eleventy blog up and running with minimal fuss. It's intentionally basic at this stage, without much styling or a fancy layout, but that suits our needs just fine for this sample application.

Now, let's take a shot at recreating the same blog, this time using Next.js.

Building a simple blog with Next.js

To create our sample blog with Next.js, we’ll need a simple folder structure similar to what we used with Eleventy. We’ll need a posts folder at the root of the project directory to hold the blog markdown files, and we’ll add the homepage and a dynamic route for individual blog pages to the page directory.

Setting up the project

This project requires a very basic setup. First, install the latest version of Next.js using the command below and follow the prompts to set up the project. For this example, we’ll use Next.js Pages Router:

npx create-next-app@latest
Enter fullscreen mode Exit fullscreen mode

Next, install gray-matter to extract metadata from the front matter of markdown files, and marked to convert the markdown files to HTML:

npm i marked gray-matter
Enter fullscreen mode Exit fullscreen mode

Once the installation and setup is complete, create a posts directory at the root for the blog posts.

Creating the content

Next, create five blogs and add content, following this format:

---
title: Post Title
date: 2022-01-02
tags: post
---

All content goes here
Enter fullscreen mode Exit fullscreen mode

In the pages directory, update the index.ts file, like so:

>import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { Key } from 'react';
export default function Home({ posts }:{posts: any}) {

  return (
    <div>
    <div className="p-2">
      <h1 className='text-[40px] mb-4'>Blog Posts</h1>
      <div className="col-lg-8">
        {posts.map((post: any, index: Key | null | undefined) => (
           <a key={index} href={`/blog/${post.slug}`} >
            <p className='mb-2'>{post.frontmatter.title}</p>
            </a>
        ))}
      </div>

    </div>
  </div>
  )
}
export async function getStaticProps() {
  const files = fs.readdirSync(path.join('posts'))
  const tempPosts = files.map((filename) => {
    const slug = filename.replace('.md', '')
    const metaMarkDown = fs.readFileSync(
      path.join('posts', filename),
      'utf-8'
    )
    const { data: frontmatter } = matter(metaMarkDown)
    return {
      slug,
      frontmatter,
    }
  })
  const posts = tempPosts.filter(
    post => {
      return post && post
    }
  )
  return {
    props: {
      posts: posts,
    },
  }

}
Enter fullscreen mode Exit fullscreen mode

Now, create a blog directory and inside it create a dynamic route to [slug].tsx so that blog will have this structure: https://nextjsblog/blog/post.

Here’s what that file looks like:

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { marked } from 'marked'
export default function PostPage({ content, frontmatter }:{content:any, frontmatter:any}) {

  return (
      <div className="container my-5">
        <div className="row">
          <div className="col-lg-10 m-auto">
            <div className='p-2'>
              <h1 className='mt-2 mb-0  text-[40px]'>{frontmatter.title}</h1>
              <h6 className='mt-0 mb-6 text-[18px] font-[500]'>{frontmatter.date} </h6>
              <div dangerouslySetInnerHTML={{ __html: marked.parse(content) }}>
              </div>
            </div>
          </div>
        </div>
      </div>
  )
}

export async function getStaticPaths() {
  const files = fs.readdirSync(path.join('posts'))
  const tempFilePaths = files.map((filename) => {
    return {
      params: {
        slug: filename.replace('.md', ''),
      },
    }
  })
  const paths = tempFilePaths.filter(
    path => {
      return path && path
    }
  )
  return {
    paths,
    fallback: false,
  }
}

export async function getStaticProps({ params: { slug } }) {
  const metaMarkDown = fs.readFileSync(
    path.join('posts', slug + '.md'),
    'utf-8'
  )
  const { data: frontmatter, content } = matter(metaMarkDown)
  return {
    props: {
      frontmatter,
      slug,
      content,
    },
  }
}
Enter fullscreen mode Exit fullscreen mode

Now each time we create a new markdown file in the posts directory, a new blog will be added to our app.

We’ve created a sample blog app in both Eleventy and Next.js; let’s record our findings from working with both tools.

Performance comparison

Here’s a comparison of page load time, Google’s Lighthouse Performance score (based on a rating scale from 0-100), caching and optimization, and data fetching and rendering for Eleventy and Next.js:

Eleventy Next.js
Page load time (Chrome DevTools Network tab metrics) 270ms 570ms
Performance (Lighthouse Performance score) 100 92
Caching and optimization More agnostic, requiring you to implement caching strategies yourself; this added flexibility means more manual work is involved in setting up and managing caching Provides more inbuilt caching options, including client-side and server-side caching, which can lead to better performance and user experience, especially for dynamic content
Data fetching and rendering More agnostic when it comes to data fetching and rendering, offering flexibility to choose data sources and rendering engines; this flexibility makes it suitable for a wide range of use cases Provides a more opinionated and integrated approach to data fetching (using SSR, SSG, or client-side data fetching) and rendering, especially when using React components

Next.js offers excellent performance, but its use of a Node.js server for server-side rendering (SSR) and API routing can introduce some complexity and potentially slower load times compared to Eleventy for static content.

Winner: For performance, Eleventy wins for pure static site generation; Next.js wins for projects requiring dynamic functionality.

Developer experience comparison

The ease of setup and the availability of tools, plugins, extensions, development server, community support, and up-to-date documentation greatly affect developer experience. Here’s a comparison of Eleventy and Next.js from a DevEx perspective:

Eleventy Next.js
Ease of setup Initial setup is more manual; project structure creation and configuration must be done from scratch; does not include an inbuilt CLI tool; the project, templating engine, and other tools must be set up by hand; provides flexibility, but may require more effort for an initial project setup, especially for those new to the tool Has an inbuilt interactive command-line tool for creating a new project; start a new project with a simple command: npx create-next-app@latest; setup process is streamlined and includes basic project structure, routing, and a sample page
Available tooling, plugins, and extensions Offers a more minimalistic approach, giving developers greater control over tooling choices and project configuration; ecosystem is growing; at this time, there are fewer available plugins and extensions Has an extensive inbuilt tooling and an ecosystem of plugins and extensions that offer a wide range of functionalities and solutions; well-suited for a variety of projects; may save on development time
Development server and hot reloading Yes Yes
Community and documentation support Good documentation; the tool is well-liked within the web development community for its simplicity and versatility; smaller community is active and supportive; numerous tutorials and resources are available Comprehensive documentation and a strong community; offers extensive resources, tutorials, and online support; framework is actively maintained and updated by the Next.js team, ensuring it stays up-to-date

Next.js offers a more streamlined and beginner-friendly setup process with its inbuilt CLI tool and default project structure. This is an advantage for those who want to get started quickly with a React-based project.

Winner: If you're looking for a quick and easy setup, especially for React-based projects, Next.js is a strong choice. On the other hand, if you prioritize flexibility and don't mind investing a bit more effort in the setup, Eleventy might be the right choice for you. The ease of setup depends on your familiarity with the tools and your project requirements.

Scalability comparison

Here’s a comparison of how Eleventy and Next.js handle larger and more complex projects:

Eleventy Next.js
Handling a growing number of blog posts Provides flexibility in data handling and content structuring; lacks the same level of inbuilt scalability features as Next.js, but offers more control over optimizing the project to handle a large number of blog posts effectively Offers a well-integrated solution for handling a growing number of blog posts; supports SSR, SSG, and ISR, along with automatic code splitting, making it highly scalable and particularly beneficial for larger blogs with dynamic content and frequent updates
Extending the app with additional features Flexibility permits the implementation of custom logic and use of external tools and services to add features; more hands-on approach may require additional development effort compared to Next.js Well-suited for adding features through the React ecosystem and its support for SSR; provides a structured way to add complex components and utilize external React libraries

Next.js is highly scalable, making it a solid choice for projects of any size. Its serverless deployment options, such as Vercel and Netlify, simplify scaling applications as needed.

Winner: Next.js wins for scalability in larger and more complex projects.

Ecosystem comparison

Eleventy has a smaller ecosystem compared to Next.js, but still offers a decent number of plugins and templates. This tool can require more custom coding for certain advanced features, but its simplicity allows for easier integration with external libraries and tools.

Eleventy’s growing and supportive community is not yet as extensive as that of Next.js, so developers may need to be more self-reliant when troubleshooting issues.

Next.js benefits from the vast ecosystem of React and Node.js. Developers can leverage a wide range of React libraries and npm packages. Additionally, Next.js enjoys a robust community with numerous resources, tutorials, and third-party packages. This strong community support can be a significant advantage when facing challenges or seeking assistance.

Winner: Next.js wins for a larger and more diverse ecosystem.

Conclusion

Our comprehensive comparison of Eleventy and Next.js reveals that the choice between these two outstanding SSG tools ultimately depends on your specific use case, project requirements, and long-term vision.

If you anticipate creating a website with a clearly defined scope, where the benefits of a static approach are evident to both you and your audience, Eleventy is the ideal choice. Its distinct features, such as minimal JavaScript, quick build times, and unwavering focus on site performance, make it the perfect solution for websites where every millisecond and kilobyte matter. These considerations may hold true for websites of all types.

But if your team has expertise working with React, or if your website project or application is on the cusp of significant growth in terms of scale and complexity, Next.js is the way to go. Next.js goes beyond static site generation, embracing a hybrid framework that seamlessly combines server-side generated pages with static ones. This unique feature makes Next.js especially compelling for content-rich websites with a large number of pages (100,000 or more), as it reduces or eliminates upfront build time.

Eleventy excels in projects focused on straightforward static site generation, while Next.js equips you with enhanced capabilities and flexibility for dynamic web applications. To make your ultimate decision, consider your project's unique requirements, your team's skills, and your vision for future project growth.


LogRocket: Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket Signup

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — start monitoring for free.

💖 💪 🙅 🚩
mangelosanto
Matt Angelosanto

Posted on December 14, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related