Modern Package.json Exports - A Complete Guide

Modern package development in Node.js has evolved significantly with the introduction of export maps and TypeScript integration. This guide covers everything you need to know about configuring exports in your package.json.

Version Requirements

To use these features, you'll need:

  • Node.js >= 12.7.0 (basic exports)
  • Node.js >= 14.13.0 (pattern exports)
  • TypeScript >= 4.7 (for typeExports and proper module resolution)

Basic Exports Configuration

The exports field in package.json defines entry points for your package:

{
  "name": "my-package",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

Advanced Subpath Exports

You can expose multiple entry points with specific conditions:

{
  "name": "my-package",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    },
    "./utils": {
      "types": "./dist/utils/index.d.ts",
      "import": "./dist/utils/index.mjs",
      "require": "./dist/utils/index.cjs"
    },
    "./components/*": {
      "types": "./dist/components/*.d.ts",
      "import": "./dist/components/*.mjs",
      "require": "./dist/components/*.cjs"
    }
  }
}

TypeScript Integration

TypeScript 4.7+ introduced enhanced support for package exports:

{
  "name": "my-package",
  "exports": {
    ".": {
      "types": "./types/index.d.ts",
      "import": {
        "types": "./types/index.d.mts",
        "default": "./dist/index.mjs"
      },
      "require": {
        "types": "./types/index.d.cts",
        "default": "./dist/index.cjs"
      }
    }
  }
}

Tree Shaking Benefits

Modern export maps enable better tree shaking:

// Before (potentially includes all utils)
import { specific } from 'my-package/utils';

// After (with proper exports)
import { specific } from 'my-package/utils/specific';

Example of a tree-shakeable configuration:

{
  "exports": {
    "./utils/*": {
      "types": "./dist/utils/*.d.ts",
      "import": "./dist/utils/*.mjs"
    }
  }
}

Compatibility Considerations

For backward compatibility with older Node.js versions, maintain the traditional fields:

{
  "name": "my-package",
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    // ... modern exports configuration
  }
}

Common Gotchas

  1. Version Mismatches: Always document minimum version requirements
  2. Build Tools: Ensure your bundler supports export maps
  3. Type Resolution: Some IDEs might need additional configuration

Recommendations

  1. Start with basic exports for the main entry point
  2. Add subpath exports gradually
  3. Test thoroughly across Node.js versions
  4. Document version requirements clearly
  5. Consider providing fallbacks for older environments

Export maps are powerful but require careful consideration of your user base's environment. When implementing these features, always ensure proper testing across different Node.js and TypeScript versions.

2025-03-18 18:002025-03-18T18:00:00.000ZNode.jsTypeScriptnpmModulesPackage Development

Copyright © 2025. All rights reserved.

Made with ❤️ by Juanman Béc