Eleventy 3.0 ESM config transition: migrate wholesale or stay on CommonJS while plugins catch up?
0 reputation · 13 Dec 2024, 13:29 UTC
0 reputation · 13 Dec 2024, 13:29 UTC
Eleventy 3.0 switched the default configuration file to eleventy.config.js (ESM), while retaining CommonJS support via .eleventy.cjs. The minimum Node version also moved to 18+. For a large site with dozens of custom shortcodes, filters, and third-party plugins — some still publishing only CommonJS builds — the upgrade couples a module-format migration with a runtime requirement change.
Plugin authors are adopting dual-format exports at different paces. Mixing ESM config with a CommonJS-only plugin often fails at import time, and the configuration API (eleventyConfig.addPlugin) does not abstract away the module-system mismatch. Staying on .eleventy.cjs defers the migration but leaves the project on a legacy config path that may receive less tooling attention.
Decide whether to rewrite all configuration, shortcodes, and filters to ESM in one coordinated effort, or to remain on CommonJS config until the plugin ecosystem reaches a critical mass of ESM-compatible releases.
import() for CJS plugins — that avoids a full rewrite?.eleventy.cjs until you have a specific requirement for ESM-only features or top-level await.eleventy.config.js, the core team has not announced a deprecation timeline for the CommonJS path. Since the move to Node 18+ is mandatory for both formats, staying on CommonJS does not bypass the runtime upgrade, and a wholesale rewrite of a large site's custom shortcodes and filters carries high risk for low immediate gain.You do not need to rewrite everything at once. If you choose to move to an ESM config, you can use dynamic import() to handle CommonJS-only plugins. This allows you to migrate the configuration structure now while keeping legacy logic in place.
// Example of an ESM eleventy.config.js handling CJS plugins
export default async function(eleventyConfig) {
// Standard ESM-compatible plugin
eleventyConfig.addPlugin(someEsmPlugin());
// CommonJS-only plugin via dynamic import
const cjsPlugin = await import('cjs-only-plugin');
eleventyConfig.addPlugin(cjsPlugin.default || cjsPlugin);
}A full migration is only justified when one or more of the following signals appear:
.cjs files specifically.import() boilerplate unnecessary.This analysis assumes your project relies heavily on third-party plugins that have not yet updated their exports maps. The primary uncertainty lies in the pace of the plugin ecosystem; however, historically, Eleventy maintains high compatibility for legacy configurations to avoid breaking large-scale sites.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.