ESM vs CommonJS vs AMD vs UMD: What's the difference?

This article does a really good job covering the differences, but in short:

ESM (ECMAScript Modules)

Official module system of JavaScript, natively supported in both browsers and Node.

Looks like:

import { foo } from "./foo.js";
export const name = "John";

Example

If you compile your TypeScript to ESM and use it with Node, you'll need to set "type": "module" in package.json to make this work.

CommonJS

Node's module system, not natively supported in browsers. Node came up with this module system before ESM existed. The recommendation now is to use ESM.

Looks like:

const foo = require("./foo.js");
module.exports = { name: "John" };

AMD (Asynchronous Module Definition)

AMD is an old module definition, now essentially obsolete. You need to include require.js to make AMD work (technically require.js and AMD are different -- AMD is a specification, require.js is an implementation of that specification).

Looks like:

define(["./foo.js"], function (foo) {
  return { name: "John" };
});

require(["index"], function (index) {
  console.log(index);
});

If you want to compile all of your TypeScript to a single file, you'll need to use AMD modules. Example.

AMD was initially created because CommonJS loaded modules synchronously, and the creators wanted a way to load them asynchronously.

ESM can do asynchronous loading, so AMD is no longer needed. ESM also has a lot of other features that AMD does not have, such as static analysis and being able to import objects and JSON files.

So there is no reason for new projects to use AMD, and RequireJS is now dead. Although you won't see that mentioned anywhere on the requirejs web page, the author says so here:

"This project is definitely in end of life mode. I’m only doing builds to fix direct dependency errors w/minor version updates, and even then only if there is a major issue."

UMD (Universal Module Definition)

UMD is a way to define modules that work in both CommonJS and AMD environments. It was a way to make your code work in both Node and the browser. But ESM works in both places now, so UMD is no longer needed.

require vs require

Both CommonJS and RequireJS/AMD use the keyword require.

CommonJS:

const foo = require("./foo.js");

RequireJS/AMD:

require(["foo"], function (foo) {});

This has confused me in the past, so calling it out explicitly here.

CommonJS vs ESM

The recommendation is to move to ESM. ESM has several advantages:

However, if you are mixing CommonJS and ESM code, here are some examples:

Further Reading

References