Course contentsShow
← Node.js
Lesson 113 of 1,9802. Module Systems and Environment ConfigurationFree lesson

Utilizing Subpath Exports for Encapsulation

Expose only specific internal paths of your library while hiding implementation details from consumers.

Utilizing Subpath Exports for Encapsulation

In this lesson, you will learn how to use exports in your package.json to act as a "bouncer" for your library, exposing only the files you want users to touch while hiding your messy internal implementation details.

Why Encapsulate?

When you publish a library, you often have a folder structure full of internal helper functions, utility scripts, and configuration files that aren't meant for public consumption. By default, users can import anything they can find by digging into your node_modules folder, such as require('my-lib/internal/secret-helper.js'). This creates a fragile experience where you cannot refactor your internal code without potentially breaking someone else’s app.

Defining Your Public API

Instead of letting users explore your entire file system, you can use the exports field in your package.json to define exactly which paths are reachable. Anything not listed here remains inaccessible.

Consider this package.json setup:

{
  "name": "my-awesome-lib",
  "exports": {
    ".": "./dist/index.js",
    "./utils": "./dist/utils.js"
  }
}

With this configuration:

  • require('my-awesome-lib') resolves to dist/index.js.
  • require('my-awesome-lib/utils') resolves to dist/utils.js.
  • require('my-awesome-lib/internal/secret-helper.js') will fail and throw an error.

By mapping public paths to your internal source files, you create a strict boundary. You are now free to rename, delete, or move files inside your internal/ folder as much as you like, because you never promised the world that those specific paths would exist. This "encapsulation" protects your library's integrity and gives you the freedom to evolve your code without breaking your users' setups.

It transforms your package from a "grab bag" of files into a professional, controlled API surface where you define the entry points and keep the implementation details private behind the scenes.

Key Takeaway: Use the exports field in package.json to define explicit entry points, effectively creating a "walled garden" that hides internal implementation details from external consumers.