Dual ESM/CJS format or clear ESM-only stance
Why it matters
A CJS-only package blocks ESM consumers entirely — they cannot use static import syntax and must resort to dynamic import() or createRequire workarounds. ESM-only packages break all CommonJS consumers (many Node.js scripts, Jest without experimental VM modules, older tools). ISO 25010 interoperability requires supporting both resolution systems until the ecosystem fully migrates. SSDF PS.3.2 flags format mismatches as a distribution integrity concern: the format published must match what consumers expect given the type field and exports conditions.
Severity rationale
High because CJS-only packages are incompatible with ESM-native bundlers and Node.js projects using `type: "module"`, and ESM-only packages break all CJS consumers.
Remediation
Configure your build tool to emit both ESM and CJS outputs and map them in package.json exports.
// tsup.config.ts — dual format output:
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
splitting: false,
clean: true
})
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"type": "module"
}
If you commit to ESM-only, set "type": "module" and document the minimum Node.js version (18+) in the engines field and README.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the SDK / Package Quality Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- iso-25010:2011 · compatibility.interoperability — Interoperability — dual ESM/CJS supports both bundler and Node.js consumers
- ssdf:800-218 · PS.3.2 — Archive and protect each software release — format contracts are part of the release
Taxons
History
- 2026-04-18·v1.0.0·Initial import from sdk-package-quality·automated