canirequire

How the data is produced

1. Registry metadata

For each package we download the full document from registry.npmjs.org, which contains the package.json of every published version. For every stable version we look at:

A version is ESM-only when it has a native ESM entry and no CommonJS entry, dual when it has both, and CommonJS when it has only a CommonJS entry. The last CommonJS version is the newest stable release that still had a CommonJS entry; ESM-only since is the first release after it that dropped CommonJS.

2. Runtime probes

Metadata can lie, so each package's latest version is also installed into an empty project and executed:

// from a .cjs file
const m = require("<pkg>");

// from a .mjs file
import * as m from "<pkg>";

Both snippets run on Node.js 18, 20, 22, 24 and 26 and on Bun 1.4. A run passes when the process exits 0 within 30 seconds. On failure we record the Node.js error code (for example ERR_REQUIRE_ESM, ERR_REQUIRE_ASYNC_MODULE, ERR_PACKAGE_PATH_NOT_EXPORTED). Failures on CommonJS packages usually point to a missing peer dependency, a browser global, or a native binary rather than a module-format problem.

1690 of 1710 packages have runtime results so far; the latest probe ran on Wed Sep 09 2026.

3. Types

A package "bundles" types when its latest version declares types/typings or a types export condition. Otherwise we check whether @types/<name> exists on npm.

Scope

The dataset covers the most-downloaded and most-depended-upon packages on npm. Pre-release versions are ignored. Download counts come from the npm downloads API.

Background: why require() of ESM is complicated

Historically require() could only load CommonJS. Node.js 22.12 (and the 20.19 backport) enabled require(esm) by default: require() can load an ES module as long as the module graph is synchronous. Packages that use top-level await still fail with ERR_REQUIRE_ASYNC_MODULE. That is why this site shows results per Node.js major instead of a single yes/no.