TechFeedTechFeed
Programming Languages

ERR_PACKAGE_PATH_NOT_EXPORTED, exports, 서브경로 | 깊은 import만 막히면?

exports가 하위 경로를 닫으면 ERR_PACKAGE_PATH_NOT_EXPORTED가 납니다. 공개 진입점으로 바꾸거나 내 패키지에 서브경로를 열고, 모듈 없음과 ESM require를 가릅니다. 다시 설치해도 같은 맵이면 호출 경로를 고칩니다. Node.js, import, 패키지, 한국 1인 개발자. 2026년 9월 노드 패키지 진입점 문서.

by

ERR_PACKAGE_PATH_NOT_EXPORTED는 패키지가 없어서가 아니라, exports가 그 하위 경로를 열지 않아 노드가 import를 거절한 줄입니다. node_modules를 지우기 전에, 에러의 슬래시 뒤 경로를 exports 키와 대조하세요.


설치는 끝났고 파일도 있는데 한 줄만 빨간 경우가 많습니다. 깊은 내부 경로는 exports가 생긴 버전부터 막힙니다.


공개 진입점으로 바꾸거나, 내 패키지면 그 서브경로를 한 줄 추가하세요. 모듈 없음, ESM을 require로 부른 에러와 문장이 다릅니다. 기준은 Node.js 패키지 진입점 문서입니다.


폴더는 있는데 그 경로만 닫힌다

패키지 폴더는 있는데, 슬래시 뒤 경로만 닫혀 있습니다.


노드 12.7부터 패키지는 exports로 바깥에 열 입구를 직접 적습니다. 이 필드가 있으면, 적히지 않은 하위 경로는 캡슐 안에 남고 패키지 이름으로는 불러올 수 없습니다. 공식 문서는 require('pkg/subpath.js')가 ERR_PACKAGE_PATH_NOT_EXPORTED를 던진다고 적습니다. 디스크의 파일이 지워진 것이 아닙니다.


에러 문장은 보통 이렇게 생깁니다. 패키지 이름, 요청한 서브경로, 그리고 그 경로가 exports에 없다는 설명입니다. 슬래시 앞은 설치된 패키지이고, 슬래시 뒤가 거절된 문입니다. 깊은 경로를 지우고 패키지가 공개한 이름만 남기면 같은 파일이라도 통과하는 경우가 많습니다.


절대 경로로 node_modules 안 파일을 직접 가리키면 노드가 예외로 읽어 주기도 합니다. 문서가 말하는 약한 캡슐입니다. 번들러와 다음 버전 업데이트는 그 구멍을 약속하지 않으니, 고치는 방법으로 쓰지 않는 편이 낫습니다.


먼저 볼 한 줄 | 에러의 슬래시 뒤를 복사해 그 패키지 package.json의 exports 키와 나란히 두세요. 키가 없으면 공개 입구가 아닙니다.


서버 랙 통로. 패키지 하위 경로가 exports에 없어 막히는 상황을 떠올리게 하는 통로 사진
폴더는 열려 있어도, exports에 없는 옆 문은 패키지 이름으로는 통과하지 않는다

exports가 여는 문

메인만 적어도 나머지 경로는 전부 닫힙니다.


문자 하나인 "exports": "./main.js"는 패키지 루트만 엽니다. 객체로 쓰면 점(".")이 루트이고, "./theme" 같은 키가 서브경로입니다. 소비자는 ui-kit/theme처럼 키와 같은 경로만 부를 수 있습니다. ui-kit/dist/theme.js처럼 파일 위치를 그대로 적으면, 그 문자열이 키에 없을 때 같은 에러가 납니다.


조건부 exports는 입구를 더 나눕니다. import와 require, types가 서로 다른 파일을 가리킬 수 있습니다. 타입 선언만 있고 런타임 키가 없으면 편집기는 조용한데 노드만 거절합니다. 개발 서버가 초록이어도 node script.js가 빨간 이유가 여기인 경우가 있습니다.


공개된 서브경로와 거절되는 깊은 경로
// ui-kit/package.json { "exports": { ".": "./dist/index.js", "./theme": "./dist/theme.js" } } import theme from 'ui-kit/theme'; // 키가 있으니 통과 import hidden from 'ui-kit/dist/theme.js'; // ERR_PACKAGE_PATH_NOT_EXPORTED

비슷한 세 문장을 가르는 표

문장 앞머리만 봐도 다음 행동이 갈립니다.


문장의미먼저 할 일
Cannot find module패키지 이름 또는 파일이 해석 경로에 없음설치, 대소문자, 작업 폴더
ERR_REQUIRE_ESM패키지는 있는데 CJS require가 ESM을 부름import로 바꾸거나 동적 import
ERR_PACKAGE_PATH_NOT_EXPORTED패키지는 있고, 그 서브경로만 비공개exports에 있는 키로 경로 수정

세 문장을 한 명령으로 밀면 시간이 늘뿐입니다. 모듈 없음은 설치와 경로 대소문자 문제이고, ESM require는 모듈 형식 문제이며, 이번 코드는 공개 입구 문제입니다. 한국에서 넥스트와 노드 스크립트를 같이 돌리는 1인 개발자라면, 페이지는 번들러가 깊은 경로를 풀어 주고 크론 스크립트만 노드 규칙으로 거절하는 장면을 자주 만납니다.


의존성을 지웠다가 다시 설치해도 exports 맵은 그대로입니다. 락파일 버전이 깊은 경로를 쓰던 예전 코드와 맞지 않으면, 설치가 초록이어도 다음 실행에서 같은 줄이 납니다.


고치는 순서

호출부를 먼저 고치고, 남 패키지의 exports는 건드리지 않습니다.


1단계는 에러에 나온 패키지 폴더의 package.json을 엽니다. exports의 키를 읽고, 내 소스의 import가 그 키와 같은지 봅니다. 점, ./theme, "./features/*" 같은 와일드카드면 별이 받는 한 조각만 허용됩니다. 와일드카드 밖의 private 폴더는 여전히 거절됩니다.


2단계는 호출을 공개 키로 바꿉니다. 체인지로그에 "deep import 제거"가 있으면 메이저 업데이트의 의도된 변화입니다. 내부 파일을 계속 부르기 위해 의존성 package.json을 손으로 고치면, 다음 설치가 그 수정을 덮습니다.


3단계는 정말 그 파일만 필요할 때입니다. 패치 도구로 내 저장소에 서브경로 키를 추가하거나, 패키지 작성자에게 공개 입구를 요청합니다. node_modules 파일을 통째로 복사해 상대 경로로 두는 방법은 라이선스와 업데이트를 함께 떠안습니다.


exports 키만 출력해 보기
node -e "const p=require('./node_modules/ui-kit/package.json'); console.log(p.exports)"
  • [ ] 에러의 패키지 이름과 슬래시 뒤 경로를 적었다
  • [ ] 그 패키지 exports 키와 호출 경로를 비교했다
  • [ ] Cannot find module, ERR_REQUIRE_ESM과 문장을 구분했다
  • [ ] 호출을 공개 키로 바꿨다
  • [ ] 남 패키지 package.json을 설치 후 손으로 고치지 않았다

내 패키지라면 서브경로를 연다

직접 배포하는 패키지면, 소비자가 부를 경로만 키로 추가합니다.


라이브러리를 한국 팀 저장소에 올려 두고 앱이 @my/kit/theme를 부른다면, 게시된 exports에 그 키가 있어야 합니다. 빌드 결과 파일이 dist에 있어도 키를 안 적으면 소비자는 같은 에러를 봅니다. 타입만 따로 열 때는 types 조건을 런타임 파일과 짝으로 둡니다.


열지 않을 파일은 키에 넣지 않습니다. 테스트 헬퍼와 내부 유틸을 공개하면 다음 리팩터마다 메이저가 됩니다. 노드 문서는 이 캡슐이 세미버 업그레이드 때 공개 인터페이스를 지키려는 장치라고 설명합니다.


소비자가 부를 키만 공개
{ "name": "@my/kit", "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js", "require": "./dist/index.cjs" }, "./theme": { "types": "./dist/theme.d.ts", "import": "./dist/theme.js" } } }
모니터가 놓인 책상. 패키지 exports 키와 import 경로를 대조하는 작업 장면
호출 경로를 exports에 적힌 키와 같게 맞추면 깊은 파일 경로는 필요 없다

번들러가 숨기는 경우 | 웹팩이나 넥스트는 개발 중에 깊은 경로를 파일로 풀어 주고, 노드로 직접 실행하는 스크립트만 거절할 수 있습니다. 페이지가 떠도 스크립트 엔트리를 한 번 실행해야 이 에러가 보입니다.


참고 자료


내부 연계: 모듈을 찾을 수 없음, ESM을 require로 부를 때, 피어 의존성 충돌


인용한 동작은 2026년 9월 Node.js 공개 문서 기준입니다.


자주 묻는 질문

node_modules를 지우면 풀리나요?

설치가 깨진 경우에는 도움이 됩니다. 이 에러는 설치된 패키지의 exports가 그 경로를 거절하는 줄이라, 다시 설치해도 같은 맵이 돌아오면 같은 문장이 납니다. 호출 경로를 공개 키로 바꾸는 쪽이 먼저입니다.


파일이 디스크에 있는데도 왜 막히나요?

exports가 있는 패키지는 파일 존재와 공개 입구를 따로 둡니다. dist 안에 파일이 있어도 키로 적히지 않으면 패키지 이름 뒤 경로로는 불러올 수 없습니다. 절대 경로 직접 로드는 문서가 말하는 예외이고, 앱 코드의 수정 방법으로는 짧습니다.


Cannot find module과 뭐가 다른가요?

모듈 없음은 이름이나 파일이 해석되지 않은 상태입니다. 이번 코드는 패키지를 찾았고, 그 안의 서브경로만 비공개라는 뜻입니다. 설치부터 하면 원인이 가려집니다.


ERR_REQUIRE_ESM과도 헷갈려요.

그건 CJS require가 ESM 전용 패키지를 부른 형식 문제입니다. 경로를 공개 키로 바꿔도 require가 남으면 다음 문장으로 넘어갑니다. 문장 코드를 먼저 읽고 형식과 입구를 나눠 고치세요.


의존성 package.json에 키를 추가해도 되나요?

다음 설치가 덮어씁니다. 꼭 필요하면 패치를 저장소에 남기고, 가능하면 공개 API로 옮기거나 작성자에게 서브경로를 요청하세요. 내부 경로는 마이너 업데이트에서도 사라질 수 있습니다.


넥스트 개발 서버는 되는데 스크립트만 실패해요.

번들러가 개발 중에 파일 경로를 풀어 주면 화면은 조용합니다. 노드로 직접 실행하는 크론이나 시드 스크립트는 exports 규칙을 그대로 적용합니다. 실패하는 그 엔트리를 한 번 실행해 경로를 확인하면 됩니다.


이 에러는 설치 실패가 아니라 공개되지 않은 서브경로입니다. exports 키와 호출을 맞추고, 내 패키지면 필요한 문만 열면 됩니다. 관련 글: 모듈을 찾을 수 없음, ESM require, 피어 충돌.


ERR_PACKAGE_PATH_NOT_EXPORTEDexports서브경로import노드패키지모듈개발자자바스크립트

함께 보면 좋은 문제 해결

EXPLORE / Programming Languages

이어서 읽어보기

전체 토픽 둘러보기 →