pnpm에서 npm으로 돌아간 이유(로컬과 CI 환경에서 직접 테스트해보기)
Description: npm을 쓰다가 pnpm을 써보면서 겪은 문제로 다시 npm을 바꾼 과정입니다. 하지만 은탄환은 없다라는 말처럼 CI환경인 경우에는 pnpm과 같은 패키지매니저의 변경이 필요해보입니다.
현재 노트: KR-020.30 a
상위 분류: KR-020.30
Why? 왜 이 글을 쓰게 되었나요?
npm
을 사용하다가 퍼포먼스 측면이 강조되고 채용 공고에서 pnpm
사용경험을 많이 묻길래 pnpm
으로 전환을 하였습니다. 하지만 사용하다보니 여러 문제로 다시 npm
으로 회귀하였고, pnpm
이 필요한 상황이나 조건이 어떤 점인지를 테스트해본 고민을 공유하기 위해 글을 작성하였습니다.
What? 어떤 문제가 있었나요?
npm
을 사용하면서 패키지 다운로드 속도와 용량 관리에 불편함을 느끼고 pnpm
으로 전환하였습니다. 하지만 pnpm
을 사용하면서 dlx
가 동작하지 않거나 마이그레이션과 같은 오버헤드뿐만아니라 결정적으로 Tailwilnd v4
를 pnpm
에서 지원이 안되는 문제를 겪었습니다.
다른 사람의 동일한 이슈(2025년 1월)
How 어떻게 해결하셨나요?
기존의 pnpm.lock.yaml
과 node_modules
를 삭제해줍니다. pnpm으로 설치된 패키지를 전부 제거한 후, npm install
을 통해 전부 새로 설치해주었습니다.
Testing 어떤 테스트를 수행 하셨나요?
몇 달간 pnpm
을 쓰면서 개인 프로젝트 수준에서는 사실 '와! 엄청 빨라졌네?' 하는 드라마틱한 체감을 하지 못했습니다. NPM 첫 다운로드도 그렇게 느리다고 느끼지 못했고, 이후 설치야 워낙 금방 되니 큰 차이를 못 느꼈죠.
Tailwind v4 이슈로 npm
으로 돌아온 후, 문득 이런 생각이 들었습니다. "그럼 도대체 어떤 경우에 pnpm
의 퍼포먼스 장점을 제대로 누릴 수 있는 걸까?" 궁금증이 커졌고, 이참에 pnpm
의 사용 이유와 원리를 좀 더 파보니 그 퍼포먼스 차이는 크게 세 가지 요소의 영향을 받는다고 생각하게 되었습니다.
바로 (패키지 사이즈 + 프로젝트 복잡성) * 설치/변경 횟수
입니다.
여기서 제가 간과했던 부분이 바로 '횟수'였습니다. 로컬 개발 환경에서는 npm install
을 처음 한두 번 하고 나면 이후에는 패키지를 추가하거나 업데이트할 때만 부분적으로 설치가 일어나니 전체 설치 속도에 크게 민감하지 않을 수 있습니다.
하지만 CI 파이프라인을 생각해보면 다르죠. 커밋할 때마다 새로운 환경에서 패키지를 '처음부터' 다운로드받고 설치하는 과정이 반복될 수 있습니다. 이럴 경우 설치 시간이 길어지면 전체 빌드 시간이 늘어나고, 클라우드 CI/CD 서비스에서는 곧 비용 증가로 이어집니다.
아, 바로 이런 환경에서 pnpm
의 캐싱 및 재사용 전략이 빛을 발하겠구나 싶었습니다. 그래서 가설을 세웠습니다. "사이즈가 크고 복잡한 프로젝트일수록, 그리고 패키지 설치가 '자주' 일어나는 환경일수록 PNPM의 이점이 클 것이다."
이 가설을 검증하기 위해 일부러 프로젝트에 사이즈가 크고 의존성이 많은 패키지를 포함시켜 npm
과 pnpm
의 설치 시간을 비교해보는 테스트를 수행했습니다. 테스트는 제 로컬 환경과 CI 환경(GitHub Actions 시뮬레이션) 두 곳에서 진행했습니다.
테스트 환경:
로컬: Windows 11, Intel i5 CPU 12450, 16GB RAM, SSD 노트북
CI 시뮬레이션:** GitHub Actions 환경 (Standard Runner 사양)
테스트 시나리오:
- 로컬 환경 - 첫 설치 (콜드 캐시/스토어):
node_modules
와 락 파일(npm의 경우package-lock.json
, pnpm의 경우pnpm.lock.yaml
)을 모두 삭제한 상태에서npm install
또는pnpm install
실행. - 로컬 환경 - 이후 설치 (웜 캐시/스토어): 첫 설치 후, 락 파일이 존재하는 상태에서
npm install
또는pnpm install
을 다시 실행 (의존성 변경 없음). - CI 환경 - 첫 설치 시뮬레이션: GitHub Actions Cache를 사용하지 않거나 캐시가 유효하지 않은 상황을 가정.
- CI 환경 - 이후 설치 시뮬레이션: GitHub Actions Cache가 유효한 상황을 가정하고 캐시를 활용하여 설치.
- CI 환경 (Cypress 추가) - 첫 설치 시뮬레이션: Cypress와 같이 매우 큰 패키지를 추가했을 때 첫 설치 시간 변화 확인.
- CI 환경 (Cypress 추가) - 이후 설치 시뮬레이션: Cypress 추가 후 캐시를 활용했을 때 설치 시간 변화 확인.
로컬 에서 테스트 시 56초, 41초로 점점 빨라지는 걸 볼 수 있습니다. npm도 cache를 상요하기 때문
$ time npm install
...
npm 1번째
real 0m56.212s
user 0m0.135s
sys 0m0.091s
npm 2번째
found 0 vulnerabilities
real 0m41.497s
user 0m0.106s
sys 0m0.108s
로컬 pnpm 첫 시도시 2분36초, 두 번째 시도시 33초
약간 놀랍게도 pnpm
의 경우 첫 설치 56초의 npm
보다 후러씬 느렸습니다. 하드링크생성, 의존성 처리가 더 복잡하기에 디스크의 스펙이 큰영향을 받다보니 노트북 환경에서는 그 차이가 더욱 두드러졌습니다. 하지만 2번 째 시도시 33초로 reused584라는 수치를 통해 pnpm
의 장점을 확인 할 수 있었습니다.
KMC@DESKTOP-GDCG9FE MINGW64 ~/Desktop/Projects/npmtest (main)
$ time pnpm install
...
Progress: resolved 585, reused 0, downloaded 584, added 584, done
real 2m35.561s
user 0m0.092s
sys 0m0.155s
KMC@DESKTOP-GDCG9FE MINGW64 ~/Desktop/Projects/npmtest (main)
$ time pnpm install
Lockfile is up to date, resolution step is skipped
Progress: resolved 584, reused 584, downloaded 0, added 584, done
real 0m33.569s
user 0m0.077s
sys 0m0.031s
CI 환경에서 드러나는 두드러지는 변화
적당히 성능이 좋은 CI 환경에서는 pnpm
이 압도적으로 빠른 속도가 나타남을 테스트할 수 있었습니다.
첫 설치시 npm
이 38초로 훨씬 느린 시간이 걸렸으며 pnpm
은 8초밖에 걸리지 않았습니다.
이후 캐시 활용한 설치 시뮬레이션에서도 크게 차이가 났엇습니다. 11초 (npm) vs 3초 (pnpm)
용량이 큰 CyPress추가하여 한 번 더 테스트 해보았을떄 초기 설치 1분 (npm) vs 8초 (pnpm) 그 차이가 훨씬 두드러졌습니다.
표로 정리하면 아래와 같습니다.
환경 | 시나리오 | PNPM 설치 시간 | NPM 설치 시간 | 핵심 인사이트 |
로컬 환경 | 첫 설치 | 2분 35초 | 56초 | PNPM 콜드 스토어 초기 구성 시간 소요 vs NPM (부분적) 웜 캐시 활용 가능. 로컬 환경 요인 영향 큼. |
이후 설치 | 33초 | 41초 | PNPM 웜 스토어 재사용 (링크 생성)이 NPM 웜 캐시 (복사/압축 해제)보다 빠름. | |
CI (기본) | 첫 설치 시뮬레이션 | 8초 | 38초 | PNPM CI 캐시(웜 스토어) 활용 vs NPM 콜드 캐시 시뮬레이션. CI에서 PNPM 캐시 효과 압도적. |
이후 설치 시뮬레이션 | 3-4초 | 9-11초 | PNPM 웜 스토어 재사용이 NPM 웜 캐시보다 훨씬 빠름. 반복적인 CI 빌드에 큰 이점. | |
CI (Cypress 추가) | 첫 설치 시뮬레이션 | 8초 | 1분 0초 | PNPM CI 캐시(웜 스토어)가 대용량 의존성(Cypress) 효율적으로 처리 vs NPM 콜드 캐시 시뮬레이션 시 시간 대폭 증가. |
이후 설치 시뮬레이션 | 4초 | 10-11초 | PNPM 웜 스토어 재사용이 NPM 웜 캐시보다 훨씬 빠름. 대용량 의존성 환경에서 PNPM의 웜 캐시 이점 부각. | |
Retrospective 무엇을 배웠고, 어떻게 활용할까요?
pnpm
을 써봤다가 다시 npm
으로 돌아오고, 이번 테스트를 통해 저는 pnpm
과 npm
각각이 빛을 발하는 환경이 다르다는 것을 확실히 깨달았습니다.
우선 제가 개인적으로 pnpm
을 쓰면서 불편함을 느꼈던 이유는 다음과 같습니다.
- 초기 마이그레이션 및 적응 오버헤드: dlx 같은 명령어 호환성 문제나, 기존에
npm
으로만 설명된 자료들을pnpm
으로 적용할 때 약간의 확인 과정이 필요했습니다. - 로컬 개발 환경에서의 '첫 설치' 체감 부족: 제 로컬 환경(노트북 SSD)과
pnpm
의 초기 설정 방식 때문에,pnpm
의 첫 설치 속도가npm
보다 오히려 느렸습니다. 로컬 환경에서의 '첫인상' 퍼포먼스는 기대에 미치지 못했습니다. - 예상치 못한 호환성 문제: Tailwind v4와 같이 특정 라이브러리와의 이슈는 언제든지 발생할 수 있으며, 이는
pnpm
사용에 대한 불안감을 주었습니다.
하지만 테스트를 통해 pnpm
의 진가가 발휘되는 지점도 명확히 확인했습니다.
- CI/CD 환경: 빌드가 자주 일어나고 매번 패키지 설치가 필요한 CI 환경에서 캐시 활용 능력과 압도적인 재설치 속도가 엄청난 이점을 제공합니다. 빌드 시간 단축은 곧 개발 생산성 향상 및 비용 절감으로 이어집니다.
- 로컬 환경의 '이후 설치' 성능: 첫 설치의 오버헤드만 감수한다면, 로컬 환경에서도 PNPM의 이후 설치/업데이트 속도가 NPM보다 빠른 것을 확인했습니다.
결론적으로, 저는 다음과 같은 기준으로 pnpm
과 npm
을 선택할 것 같습니다.
- 개인 프로젝트, 소규모 팀 프로젝트 (CI 빈도가 낮거나 중요도가 떨어지는 경우):
npm
으로도 충분하다고 생각합니다. 로컬 첫 설치 성능 저하 가능성, 마이그레이션/호환성 오버헤드를 감안하면 익숙한 도구를 사용하는 것이 효율적일 수 있습니다. - 대규모 팀 프로젝트, CI/CD 의존도가 매우 높은 프로젝트:
pnpm
사용을 강력하게 고려할 것 같습니다. 초기 도입 및 호환성 검토 비용이 있더라도, CI 시간 단축으로 인한 생산성 향상 및 비용 절감, 대규모/모노레포 환경에서의 효율적인 패키지 관리 등 얻게 되는 장점이 훨씬 클 것이기 때문입니다.
이번 경험을 통해 단순한 벤치마크 숫자나 듣기만 한 경우가 아닌 **'자신의 프로젝트 환경과 사용 패턴, 그리고 중요하게 생각하는 지점(로컬 첫 설치 속도 vs CI 속도 vs 디스크 용량 vs 호환성 등)'**에 맞는 도구를 선택하는 것이 가장 중요하다는 것을 다시 한번 느꼈습니다.
앞으로는 새로운 프로젝트를 시작하거나 기존 프로젝트의 패키지 매니저 변경을 고려할 때, 단순히 '요즘 뜨는 도구'가 아니라 프로젝트의 규모, 팀의 숙련도, CI/CD 환경, 로컬 개발 환경의 특성 등 다양한 요소를 종합적으로 판단하여 가장 적합한 도구를 선택하여야함을 느끼고, 이번 테스트 경험은 그런 판단을 내리는 데 큰 도움이 될 것입니다.