# Compile Typescript Libraries to Multiple Formats {% youtube src="https://youtu.be/Vy4d0-SF5cY" title="Packaging Typescript Lbraries" width="100%" /%} It can be difficult to set up a typescript library to compile to ESM and CommonJS. As of Nx 16.8, you can use the `@nx/rollup:rollup` executor to take care of it for you. ## Use Rollup to Compile your TypeScript Project If you do not use Rollup already, install the corresponding Nx plugin as follows: {% tabs %} {%tab label="npm"%} ```shell npm add -D @nx/rollup ``` {% /tab %} {%tab label="yarn"%} ```shell yarn add -D @nx/rollup ``` {% /tab %} {%tab label="pnpm"%} ```shell pnpm add -D @nx/rollup ``` {% /tab %} {% /tabs %} Make sure the version of `@nx/rollup` matches your other `@nx/*` package versions. You can then configure Rollup to compile your library by adding a `build` target to your `project.json` or `package.json` file. Here's an example: {% tabs %} {%tab label="package.json"%} ```jsonc {% fileName="packages/my-awesome-lib/project.json" %} { "name": "my-awesome-lib", "nx": { "targets": { "build": { "executor": "@nx/rollup:rollup", "options": { "main": "packages/my-awesome-lib/src/index.ts" } } } } } ``` {% /tab%} {%tab label="project.json"%} ```jsonc {% fileName="packages/my-awesome-lib/project.json" %} { "name": "my-awesome-lib", "targets": { "build": { "executor": "@nx/rollup:rollup", "options": { "main": "packages/my-awesome-lib/src/index.ts" } } } } ``` {% /tab%} {% /tabs %} If you happen to use the `@nx/js:tsc` executor already, you can also use the [Rollup configuration](/nx-api/rollup/generators/configuration) generator from the Nx Rollup plugin to automatically configure your project's build target. ## Configure Rollup to Create Multiple Formats You'll need to specify `format`, `additionalEntryPoints` and `generateExportsField` in the executor options. Here's an example: ```jsonc {% fileName="packages/my-awesome-lib/project.json" highlightLines=["8-10"] %} { "name": "my-awesome-lib", "targets": { "build": { "executor": "@nx/rollup:rollup", "options": { "main": "packages/my-awesome-lib/src/index.ts", "format": ["esm", "cjs"], "additionalEntryPoints": ["packages/my-awesome-lib/src/foo.ts"], "generateExportsField": true } } } } ``` After compiling our package using `nx build my-awesome-lib` we'll get the following output in our `dist` folder. ``` my-awesome-lib └─ . ├─ README.md ├─ foo.cjs.d.ts ├─ foo.cjs.js ├─ foo.esm.js ├─ index.cjs.d.ts ├─ index.cjs.js ├─ index.esm.js ├─ package.json └─ src ├─ foo.d.ts ├─ index.d.ts └─ lib └─ my-awesome-lib.d.ts ``` And our `package.json` will look like this: ```json {% fileName="dist/my-awesome-lib/package.json" %} { "name": "my-awesome-lib", "version": "0.0.1", ... "type": "commonjs", "main": "./index.cjs.js", "typings": "./src/index.d.ts", "exports": { "./package.json": "./package.json", ".": { "import": "./index.esm.js", "default": "./index.cjs.js" }, "./foo": { "import": "./foo.esm.js", "default": "./foo.cjs.js" } }, "module": "./index.esm.js" } ``` Now consumers of your package can access the appropriate format for their codebase and you don't have to worry about maintaining the infrastructure to compile to both formats.