Skip to navigation Skip to main content
The possum is Eleventy’s mascot
Stable
3.0.0
Canary
3.0.1-alpha.5
Menu
Eleventy 5.81s
Remix 40.14s

CommonJS vs. ESM

Contents

Historically, Eleventy (prior to version 3) has worked with the Node.js default flavor of JavaScript modules: CommonJS. Practically speaking, this means you used module.exports and require() in any .js (or .cjs) files in your project. This affected Configuration files, JavaScript Data Files, and JavaScript (.11ty.js) templates.

However, ESM (ECMAScript Modules) are a newer JavaScript standard that will work in more JavaScript environments and runtimes. Instead of module.exports and require(), you’ll use export and import().

Runtimes

Jump to section titled: Runtimes

Node.js

Jump to section titled: Node.js

If you want to start using ESM in your project, there are two ways to do it in Node.js (both of which work fine in Eleventy v3):

  1. Project-wide: Adding "type": "module" in your package.json, which swaps the default for .js files from CommonJS to ESM.
  2. Individual files (incremental migration): by using the .mjs file extension instead of .js you can change a single file to use ESM.

You can also choose to keep using CommonJS in your Eleventy project: using ESM is not required. Eleventy will continue to support CommonJS moving forward. Our documentation shows both CommonJS and ESM versions of each JavaScript code snippet.

.js, .cjs, and .mjs file extensions are supported for Configuration Files, JavaScript Data Files and JavaScript (.11ty.js) templates.

Configuration

Jump to section titled: Configuration

Read more about supported configuration file names.

CommonJS Configuration

Jump to section titled: CommonJS Configuration

If you use Eleventy bundled plugins (e.g. I18nPlugin, RenderPlugin, or HTMLBasePlugin, among others), you will not be able to require Eleventy directly in your configuration file.

Consider this CommonJS configuration file:

// Any combination of these
const { I18nPlugin, RenderPlugin, HtmlBasePlugin } = require("@11ty/eleventy");

module.exports = function (eleventyConfig) {
// …
};

In Eleventy v3 you’ll need to use a dynamic import() instead of require (or change your configuration file to use ESM):

module.exports = async function (eleventyConfig) {
const { I18nPlugin, RenderPlugin, HtmlBasePlugin } = await import("@11ty/eleventy");
// …
};

Note the async configuration callback. This change is to work around limitations in Node.js with require("ARBITRARY_ESM_PACKAGE"). Future versions of Node.js may fix this limitation.

If you attempt to require("@11ty/eleventy") with Eleventy v3, we’ll throw a very helpful error message which will provide you exact instructions on how to fix the issue.

default and ESM plugins

Jump to section titled: default and ESM plugins

When using plugin code that uses the default export as the plugin callback, you will need to use the special default property supplied from dynamic import().

module.exports = async function (eleventyConfig) {
const { default: myPlugin } = await import("my-eleventy-plugin");
// …
};

ESM Configuration

Jump to section titled: ESM Configuration

Your configuration file using ESM will look like this:

// Any combination of these
import { I18nPlugin, RenderPlugin, HtmlBasePlugin } from "@11ty/eleventy";

export default function (eleventyConfig) {
// …
};

Note the use of import and export default.

Plugins

Jump to section titled: Plugins

You can write your Eleventy plugins in CommonJS or ESM too.

  • If you write them in ESM you’ll have to instruct folks to use the same approach as above (using dynamic import()).
  • CommonJS plugins will work without additional instruction needed (you can import a CommonJS package directly without incident).

Other pages in Learn: