# To Bundle or Not to Bundle Your TypeScript Types

By [Florian Martens](https://pipe0.com/authors/florian-martens) · Published Apr 14, 2025

Source: https://pipe0.com/blog/when-to-bundle-typescript-types

> Learn when bundling your TypeScript types makes sense



Even for experienced TypeScript engineers, the difference between "bundled" and "unbundled" types
can be confusing. Digging into this topic can help you create better libraries and consume 3rd-party libraries better.

## What is Bundling? [#what-is-bundling]

When building a TypeScript library with tools like `tsc`, the module structure is preserved by default.

For example, if your library has a `src/index.ts` and `src/utils.ts` file, you will see `dist/index.d.ts`
and `dist/utils.d.ts` in the build output. In this case, your types are **unbundled**.

If you explore types of an unbundled library, e.g., by `cmd + click` in VS Code, your IDE will take you
to the declaration file where that type was defined. The declaration file will only contain the types of that module
and not the types of the whole library.

In contrast, **bundling** `d.ts` files means combining `d.ts` files into a single file that contains all the types for your entire library.
Bundling is typically done with tools like [`rollup-plugin-dts`](https://www.npmjs.com/package/rollup-plugin-dts). With bundling, the module
structure of your source files is lost.

If you explore the types of a bundled library, you navigate through one large file. Let's explore when it makes
sense to bundle your TypeScript types.

## TL;DR [#tldr]

The general best practice is: **type declarations should align with your JavaScript distribution files**. So,
if you use a bundler to bundle all your TypeScript files into one large bundled JavaScript file, you should
bundle your types into one large file. This ensures that:

* Your JavaScript and `d.ts` files are consistent.
* Your declaration files don't expose files that don't exist in your JavaScript bundle (this happens when your JavaScript is bundled but your declarations are not).

To answer whether you should bundle your declaration files is to answer the question of whether you should bundle
your JavaScript files. &#x2A;*Use this rule of thumb: Don't bundle your types until you have a good reason to bundle them.**

## Good Reasons to Bundle JavaScript Files [#good-reasons-to-bundle-javascript-files]

1. Your library is consumed by an environment that expects a bundled file (e.g., browser or CommonJS).
2. Consumers of your library do not use a bundler and require a small library footprint.

## When to Keep Types Unbundled [#when-to-keep-types-unbundled]

Not bundling your types is a good default because:

1. Most consumer code uses a bundler before shipping to the browser or running on the server.
2. You can use declaration maps to make navigating types easier by linking to source code in editors.

## A Special Case for the `exports` Property? [#a-special-case-for-the-exports-property]

The [`exports` property](https://nodejs.org/api/packages.html#package-entry-points) of the `package.json` file
allows defining entry points of a package. It's supported in Node.js 12+ and all other modern JavaScript runtimes.

```json
{
  "exports": {
    ".": "./dist/index.js",
    "./utils": "./dist/utils.js"
  },
  "types": "./dist/index.d.ts"
}
```

One feature of the `exports` property is restricting module imports. It prevents consumers of a library from importing internal files.
When the `exports` property is specified, imports like `import { X } from 'lib/internal/foo'` will fail unless `lib/internal/foo` is a
valid entry point listed in the `exports` property.

In many ways, defining a root entry point with the `exports` property for `.` makes your library behave like it is bundled - even if it is not.
This is because the `exports` property hides internal APIs the same way bundling does.

When using the `exports` property, you might think there’s a stronger case to use bundled types, since you're emulating the behavior
of a bundled library. However, even when using the `exports` property, having **unbundled types should still be your default**, since it
adds less complexity to your build setup. For multi-entry libraries, TypeScript can resolve unbundled types (e.g., dist/utils.d.ts for lib/utils)
as long as they match your exports paths.

If you bundle types and have multiple entry points, consider bundling per entry point with tools like rollup-plugin-dts to maintain modularity.
