Node.js모듈과 패키지

package exports, imports, conditional exports

`package.json`의 `exports`와 `imports` 필드, conditional exports가 패키지 공개 경계를 어떻게 정하는지 정리합니다.

마지막 수정 2026년 3월 22일

기본 패턴

json
{
  "exports": {
    ".": "./dist/index.js",
    "./cli": "./dist/cli.js"
  },
  "imports": {
    "#internal/*": "./src/internal/*.js"
  }
}

설명

  • exports는 "이 패키지가 외부에 어떤 진입점만 공개할 것인가"를 선언하는 필드입니다. 즉 단순 진입 파일 지정이 아니라 공개 API 경계를 타입 수준이 아니라 패키지 수준에서 정하는 장치입니다.
  • main만 쓰던 시절과 달리 exports를 쓰면 서브패스 공개, 비공개 내부 파일 캡슐화, 환경별 분기까지 더 정교하게 다룰 수 있습니다.
  • conditional exports는 같은 패키지라도 import로 읽힐 때와 require로 읽힐 때, 또는 node/default 환경에 따라 다른 엔트리포인트를 내보내게 해 줍니다. dual package 전략에서 자주 등장합니다.
  • imports는 반대로 현재 패키지 내부에서만 쓰는 alias를 정의하는 필드입니다. #로 시작하는 private specifier를 통해 긴 상대 경로를 줄이고 내부 경계를 더 명확히 할 수 있습니다.
  • 이 카드는 결국 "패키지 공개면"을 어떻게 설계할 것인가에 대한 주제입니다. 코드 구조를 폴더로만 정리하는 것과, Node가 실제로 허용하는 public entrypoint를 선언하는 것은 다른 차원의 문제입니다.

빠른 정리

필드역할
exports외부 공개 엔트리포인트 선언
conditional exports환경/모듈 방식별 다른 엔트리 제공
imports패키지 내부 전용 alias
장점캡슐화, 서브패스 제어, dual entrypoint 지원
핵심 판단실제 public API가 어디까지인지 먼저 정함

주의할 점

exports를 도입하면 예전에 우연히 접근되던 내부 파일이 더는 보이지 않을 수 있습니다. 즉 단순 리팩터링이 아니라 패키지 계약을 재정의하는 변화로 보는 편이 맞습니다.

참고 링크

1 sources