Configuring module format
Modern SDKs need to balance compatibility with performance. The moduleFormat option in the SDK generator allows developers to control whether an SDK is built for CommonJS (CJS), ECMAScript Modules (ESM), or both. This choice impacts bundle size, tree-shaking performance, and compatibility with Node.js and modern bundlers.
How to configure module format
To configure the module format, update the typescript section of your gen.yaml file (which is often located in the SDK’s .speakeasy directory):
typescript:
# add or modify `moduleFormat`
moduleFormat: "esm" # or "dual" or "commonjs"
# other Typescript configuration options...Supported options
Select one of the supported module formats:
"esm"is the default option for new SDKs. It builds SDKs for ECMAScript Modules. ESM is the modern standard for JavaScript modules, providing optimal tree-shaking and significantly smaller bundles when used with bundlers like Webpack, Rollup, or Vite."dual"is the default option for existing SDKs. By building SDKs for both CJS and ESM formats, it offers ESM’s superior tree-shaking and bundle optimization while maintaining compatibility with older CJS environments. The slight build time increase is often worth the flexibility and performance benefits."commonjs"builds SDKs for CommonJS. CJS is widely supported across Node.js environments, but it’s less optimized for modern bundlers and tree-shaking.
Module format overview
The moduleFormat determines the module system targeted during SDK building. It impacts:
- Node.js project compatibility
- Bundler tree-shaking capabilities
- SDK bundle size
- Build performance
Example outputs
Review the different outputs generated for each module format.
CJS
The commonjs module format outputs the following:
// CommonJS import in consumer code
const { ApiError } = require("petstore/errors/apierror.js");
// ESM import (interop code included)
import { ApiError } from "petstore/errors/apierror.js";ESM
The esm module format outputs the following:
// Native ESM import in consumer code
import { ApiError } from "petstore/errors/apierror.js";
// ❌ Will not work in CommonJS-only environmentsDual
The dual module format outputs the following:
// ESM import (no interop code)
import { ApiError } from "petstore/errors/apierror.js";
// CommonJS import (still works seamlessly)
const { ApiError } = require("petstore/errors/apierror.js");How to decide which format to use
We recommend using ESM (esm) if:
- Most modern tooling supports ESM, and building for just one target simplifies the build chain.
- Tree-shaking and bundle size optimization are top priorities.
- The project already uses ESM throughout.
- Leveraging the latest JavaScript features and tooling is important.
We recommend using both (dual) if:
- You require support for both modern and legacy environments.
- You need ESM’s superior tree-shaking while maintaining CJS compatibility.
- The SDK is used in diverse environments with different module requirements.
- Developer experience and maximum flexibility are priorities.
We recommend using CJS (commonjs) if:
- Bundle size optimization is not a critical requirement.
- You require maximum compatibility with legacy systems.
Recommendation
For most projects, esm is the best choice. Most modern tooling supports ESM, and building for a single target simplifies the build chain while providing optimal tree-shaking and bundle size.
Additional reading
Last updated on