# Configuring module format
Source: https://speakeasy.com/docs/sdks/customize/typescript/configuring-module-format

    
import { Callout } from "@/mdx/components";



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):

```yaml filename="<sdk-root>/.speakeasy/gen.yaml"
typescript:
  # add or modify `moduleFormat`
  moduleFormat: "commonjs" # or "esm" or "dual"
  # other Typescript configuration options...
```

### Supported options

Select one of the supported module formats:

- `"commonjs"` is the default option. It builds SDKs for CommonJS. CJS is widely supported across Node.js environments, but it's less optimized for modern bundlers and tree-shaking.
- `"esm"` is the modern standard for JavaScript modules. It builds SDKs for ECMAScript Modules. ESM provides optimal tree-shaking and significantly smaller bundles when used with bundlers like Webpack, Rollup, or Vite.
- `"dual"` provides the best of both worlds. 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.

## 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:

```javascript filename="example.js"
// 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:

```javascript filename="example.js"
// Native ESM import in consumer code
import { ApiError } from "petstore/errors/apierror.js";

// ❌ Will not work in CommonJS-only environments
```

#### Dual

The `dual` module format outputs the following:

```javascript filename="example.js"
// 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 CJS (`commonjs`) if:

- The SDK is used primarily in Node.js environments or older projects.
- Bundle size optimization is not a critical requirement.
- You require maximum compatibility with legacy systems.

We recommend using ESM (`esm`) if:

- The SDK consumers use modern bundlers like Vite, Webpack, or Rollup.
- 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.

<Callout title="Recommendation" type="info">
For most modern projects, the `dual` format is best. It ensures the SDK works smoothly in any environment, while still providing the performance benefits of ESM when used with modern bundlers.
</Callout>

## Additional reading

- [TypeScript configuration options](/docs/gen-reference/ts-config)
- [Lean SDKs with standalone functions](/post/standalone-functions)