How to create an npm package with tsup

Learn how to create an npm package with tsup for Node.js with ESM, CJS and, types support.

4 min read

views

In this article, you will learn how to create an npm package. We will use tsup to build our package, it allows us to easily output ESM and CJS code together with our TypeScript types. We will also be using TypeScript to write our code.

Project Setup

Firstly, we will create a folder for our project and initialize the project with npm.

mkdir my-project && cd my-project && npm init -y
bash

This will create a package.json file for us. Now, we can install the necessary development dependencies:

npm i -D tsup typescript @types/node
bash

While it is installing the dependencies, we can create a src folder and a src/index.ts file.

mkdir src && touch src/index.ts
bash

Now, we can add the following code to src/index.ts:

src/index.ts
// replace this with actual code later ;)
export function hello(name: string) {
  return `Hello ${name}!`;
}
ts

Tooling Setup

TypeScript configuration

Now that we have our project setup, we can add TypeScript to our project. Start by creating a tsconfig.json file:

touch tsconfig.json
bash

Now, simply add the following configuration to our tsconfig.json file:

Tip: you can also add more configuration options to this file if necessary.

tsconfig.json
{
  "compilerOptions": {
    "outDir": "./dist",
    "target": "ESNext",
    "moduleResolution": "node",
    "declaration": true,
    "skipLibCheck": true,
    "esModuleInterop": true
  },
  "exclude": ["dist", "node_modules"]
}
json

Package scripts

Now that we have our project setup, we can add the following scripts to our package.json file:

package.json
{
  "name": "my-package",
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch"
  }
}
json
  • build: This will build our package and output it to the dist folder.
  • dev: This will build our package and watch for changes.

npm config

Now that we have our project setup, we can add the following exports and type to our package.json file. This will allow users to use both ESM and CJS versions of our package.

package.json
{
  "name": "my-package",
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch"
  },
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    },
    "./package.json": "./package.json"
  }
}
json

ESM Only?!

Nope! This package is not ESM only. You may have noticed we added the "type": "module" but this is only for the package.json file. We also added the "exports" field, which will allow us to use both ESM and CJS versions of our package.

tsup configuration

Once the scripts have been added, we have to add the following tsup configuration to our package.json file:

package.json
{
  "name": "my-package",
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch"
  },
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    },
    "./package.json": "./package.json"
  },
  "tsup": {
    "dts": true,
    "bundle": false,
    "treeshake": true,
    "target": "node18",
    "format": ["esm", "cjs"],
    "entry": ["src/**/*.ts"]
  }
}
json
  • dts: This will generate *.d.ts files for our package. These will be used to provide type support for our package.
  • bundle: Setting this to false will prevent tsup from bundling our package into a single file.
  • target: Make sure the output code is compatible with Node.js v18 or higher.
  • format: This will generate both ESM and CJS versions of our package.
  • entry: The entry files to our package.

Publishing

To publish our package, login to your npm account.

npm login
bash

Now, we can publish our package.

npm publish
bash

That's it!

Now, we have successfully created an npm package with tsup for Node.js with ESM, CJS and, types support.

Checkout the GitHub repository for the full source code.