Skip to navigation Skip to main content

CommonJS, ESM, and TypeScript

On this page

Eleventy works with many different flavors of JavaScript:

  • CommonJS: the original flavor of Node.js, for broadest compatibility with older versions of Node.js.
  • ECMAScript Modules (ESM) (recommended): the new JavaScript standard for future-friendly code. This is most compatible with alternative JavaScript environments and runtimes (browsers, even!).
  • TypeScript: adds types to JavaScript. Typically requires transpilation but natively supported in Node.js (via type stripping in Node 22.6+) and Deno.

Compatibility

Eleventy is compatible with ESM, CommonJS, and TypeScript (with some runtime limitations). Note the following:

Feature CommonJS ESM TypeScript (CommonJS) TypeScript (ESM)
@11ty/eleventy Compatibility v0+ v3+ v3+ (additional configuration required) v3+ (additional configuration required)
.js files use (unless package.jsontype) .js in Node.js .js in Deno - -
.ts files use (unless package.jsontype) - - .ts in Node.js .ts in Deno
Explicit File Extension .cjs .mjs .cts .mts
Node.js Compatibility Node.js * Node.js v12.20+ Node.js v22.6+ Node.js v22.6+
Deno Compatibility Deno v2+ Deno * Deno v2+ Deno *

You can mix and match different flavors when using the following Eleventy project files and features:

JavaScript Runtimes

Eleventy has goals to broadly support the same module formats as your chosen JavaScript runtime.

Node.js and Deno

CommonJS, ESM, and TypeScript are supported in Node.js and Deno.

If you want to use ESM (in JavaScript or TypeScript) in your Eleventy (v3+) project, you can do this project-wide or incrementally on a per-file basis:

  1. Project-wide: Adding "type": "module" in your package.json, which specifies that .js (and .ts) files use ESM (this is the default in Deno, swap back to CommonJS using "type": "commonjs"). When using ESM, use .cjs (or .cts) file extensions to mark individual files as CommonJS.
  2. Individual files (incremental migration): by using the .mjs (and .mts) file extension instead of .js you can change a single file to use ESM.

If your Eleventy project already uses CommonJS, you can keep using CommonJS: using ESM is not required. Eleventy will continue to support CommonJS moving forward. Our docs include code snippets for both CommonJS and ESM.

.js, .cjs, and .mjs file extensions are supported for Configuration Files, JavaScript Data Files and JavaScript (.11ty.js) templates. With additional configuration, you can use .ts, .cts, and .mts file extensions for TypeScript for these features as well.

Configuration

Read more about supported configuration file names.

ESM Configuration

Your configuration file using ESM can use Eleventy bundled plugins (like i18n, Render, InputPath to URL, id Attribute or HTML <base>) directly:

// Any combination of these import { I18nPlugin, RenderPlugin, HtmlBasePlugin } from "@11ty/eleventy"; export default function (eleventyConfig) { // … };

Note the use of import and export default.

CommonJS Configuration

If you use Eleventy bundled plugins (like i18n, Render, InputPath to URL, id Attribute or HTML <base>), you have a few options to use Eleventy v3 in your configuration file.

Consider this CommonJS configuration file:

// This requires Node v20.19 or newer const { I18nPlugin, RenderPlugin, HtmlBasePlugin } = require("@11ty/eleventy"); module.exports = function (eleventyConfig) { // … };

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

CommonJS Configuration in Node 18

For older versions of Node.js, 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.

Using ESM plugins in CommonJS Configuration

You can use any third-party plugin written in ESM using the same approach. Keep in mind that using 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"); // … };

Plugins

You can write your Eleventy plugins in CommonJS or ESM too. Which should you choose?

Feature ESM or CommonJS
Compatibility with Eleventy v3 and newer ✅ ESM
Compatibility with Eleventy v2 or older ✅ CommonJS
Compatibility with Node 20.19+ ✅ ESM
Compatibility with older Node < 20.19 ✅ CommonJS

Notably, the same limitations documented above for Eleventy bundled plugins will apply to your plugin code as well!


Other pages in Learn