2025-08-31 13:13

  • npm은 자바스크립트 런타임 환경인 Node.js의 기본 패키지 관리자로, 전 세계 개발자들이 코드를 공유하는 거대한 온라인 저장소(Registry)와 상호작용합니다.

  • package.json 파일은 프로젝트의 정보와 의존성을 명시하는 설계도 역할을 하며, npm install 명령어로 필요한 모든 패키지를 node_modules 폴더에 설치합니다.

  • npm은 단순한 패키지 설치를 넘어 스크립트 실행, 버전 관리(package-lock.json), 보안 감사(npm audit) 등 현대 웹 개발의 생산성을 책임지는 핵심 도구입니다.

개발자라면 반드시 알아야 할 npm 핸드북 A to Z

자바스크립트로 무언가를 만들어 본 개발자라면 npm이라는 단어를 한 번쯤은 들어보셨을 겁니다. “npm install”이라는 명령어는 마치 개발을 시작하는 주문처럼 느껴지기도 합니다. 하지만 npm이 정확히 무엇이고, 왜 만들어졌으며, 어떻게 우리의 개발 생활을 편리하게 만들어 주는지 깊이 있게 이해하는 것은 또 다른 차원의 이야기입니다.

이 핸드북은 npm의 탄생 배경부터 핵심 구조, 필수적인 사용법, 그리고 더 나아가 고급 활용 팁까지, npm의 모든 것을 총망라하여 설명합니다. 이 글을 끝까지 읽으신다면, 여러분은 npm을 단순한 명령어 입력 도구가 아닌, 현대 자바스크립트 생태계의 심장을 움직이는 강력한 엔진으로 이해하게 될 것입니다.

1. npm은 왜 만들어졌을까? 카오스 속에서 피어난 질서

npm의 등장을 이해하기 위해서는 그 이전의 자바스크립트 개발 환경을 상상해봐야 합니다. 지금처럼 체계적인 모듈 시스템이나 패키지 관리자가 없던 시절, 개발자들은 필요한 라이브러리나 프레임워크를 어떻게 사용했을까요?

정답은 ‘직접 다운로드해서’ 입니다.

예를 들어, 웹 페이지에 화려한 슬라이드를 추가하기 위해 ‘SuperSlider.js’라는 라이브러리가 필요하다고 가정해 봅시다. 개발자는 해당 라이브러리의 공식 웹사이트에 방문하여 .js 파일을 직접 다운로드하고, 프로젝트 폴더에 복사한 뒤, HTML 파일에 <script> 태그로 일일이 추가해야 했습니다.

이 방식에는 몇 가지 치명적인 문제점이 있었습니다.

  • 의존성 지옥 (Dependency Hell): ‘SuperSlider.js’가 ‘jQuery’ 1.8 버전을 필요로 하는데, 내 프로젝트의 다른 라이브러리는 ‘jQuery’ 2.0 버전을 필요로 한다면 어떻게 될까요? 두 버전이 충돌하여 웹페이지 전체가 망가지는 ‘의존성 지옥’에 빠지기 쉬웠습니다.

  • 수동 업데이트의 번거로움: ‘SuperSlider.js’에 보안 취약점이 발견되어 1.1 버전이 새로 나왔다면? 개발자는 이 사실을 직접 인지하고, 다시 웹사이트에 방문해 새 파일을 다운로드하여 교체해야 했습니다. 프로젝트가 커지고 사용하는 라이브러리가 수십 개가 되면 이는 거의 불가능에 가까운 작업이었습니다.

  • 공유와 협업의 어려움: 내가 만든 유용한 함수들을 다른 사람과 공유하고 싶어도 마땅한 방법이 없었습니다. 그저 블로그에 코드를 올리거나 압축 파일로 전달하는 원시적인 방법에 의존해야 했습니다.

이러한 혼돈의 시대에 Node.js가 등장했습니다. Node.js는 자바스크립트를 브라우저 밖(서버 등)에서도 실행할 수 있게 해준 혁신적인 런타임 환경이었습니다. 중요한 것은 Node.js가 CommonJS라는 모듈 시스템을 채택하여, 코드를 재사용 가능한 작은 단위(모듈)로 나누고 require() 함수로 손쉽게 불러올 수 있는 길을 열었다는 점입니다.

체계적으로 모듈을 관리할 수 있게 되자, 자연스럽게 “이 모듈들을 어디선가 한데 모아 관리하고, 쉽게 다운로드하고, 버전 충돌 없이 사용할 수 있는 도구가 필요하다!”는 요구가 폭발적으로 증가했습니다.

바로 이 문제를 해결하기 위해 2010년, Isaac Z. Schlueter에 의해 **npm (Node Package Manager)**이 탄생했습니다. npm은 자바스크립트 개발에 필요한 모든 코드 조각(패키지)을 위한 거대한 온라인 도서관(Registry)이자, 그 도서관에서 원하는 책(패키지)을 빌리고 관리해 주는 똑똑한 사서(CLI) 역할을 자처했습니다.

2. npm의 핵심 구조 파헤치기

npm은 크게 세 가지 핵심 요소로 구성됩니다. 이 세 가지를 이해하면 npm이 어떻게 동작하는지 명확하게 파악할 수 있습니다.

2.1. npm 레지스트리 (npm Registry)

전 세계의 자바스크립트 개발자들이 만든 수백만 개의 패키지가 저장되어 있는 거대한 온라인 데이터베이스입니다. 우리가 npm install 명령어를 실행하면, npm CLI는 바로 이 레지스트리에 접속하여 필요한 패키지를 찾아 다운로드합니다. 누구나 자신이 만든 패키지를 이곳에 등록하여 전 세계 개발자들과 공유할 수 있으며, 이는 자바스크립트 생태계가 폭발적으로 성장하는 원동력이 되었습니다.

2.2. npm CLI (Command Line Interface)

우리가 터미널이나 명령 프롬프트에서 직접 상호작용하는 도구입니다. npm install, npm start 와 같은 명령어를 통해 npm 레지스트리와 소통하고, 프로젝트의 의존성을 관리하며, 스크립트를 실행하는 등 npm의 모든 기능을 제어하는 역할을 합니다. Node.js를 설치하면 자동으로 함께 설치됩니다.

2.3. package.json

package.json 파일은 프로젝트의 심장이라 할 수 있는 가장 중요한 파일입니다. 이 파일은 단순한 JSON 형식이지만, 프로젝트에 대한 모든 메타데이터와 의존성 정보를 담고 있습니다. 마치 건물의 설계도와 같아서, 이 파일만 있으면 언제 어디서든 동일한 개발 환경을 구축할 수 있습니다.

주요 속성들은 다음과 같습니다.

속성 (Property)설명
name패키지의 이름. npm 레지스트리에서 유일해야 합니다.
version패키지의 버전. 유의적 버전(Semantic Versioning) 규칙을 따릅니다. (Major.Minor.Patch)
description패키지에 대한 간략한 설명.
main패키지의 진입점(entry point)이 되는 파일 경로. 보통 index.js 입니다.
scripts프로젝트에서 자주 사용하는 명령어들을 등록하는 곳. npm run <스크립트이름>으로 실행할 수 있습니다.
dependencies프로덕션 환경(실제 서비스)에서 필요한 패키지들. 애플리케이션이 동작하기 위해 반드시 필요한 라이브러리입니다.
devDependencies개발 환경에서만 필요한 패키지들. 테스트 도구, 번들러, 코드 포맷터 등 개발 과정에만 사용되는 라이브러리입니다.
author패키지 제작자 정보.
license패키지의 라이선스 (예: “MIT”, “ISC”).

특히 dependenciesdevDependencies의 구분은 매우 중요합니다. 예를 들어, 리액트(React)는 애플리케이션을 구동하는 데 필수적이므로 dependencies에 속하지만, 코드를 테스트하는 Jest는 실제 서비스에서는 필요 없으므로 devDependencies에 속합니다.

2.4. node_modules와 package-lock.json

  • node_modules: npm install을 실행했을 때 npm 레지스트리에서 다운로드한 모든 패키지의 실제 코드가 저장되는 폴더입니다. 프로젝트가 사용하는 모든 의존성 패키지와 그 패키지들이 의존하는 또 다른 패키지들이 트리 구조로 얽혀있어 종종 용량이 매우 커지곤 합니다. Git과 같은 버전 관리 시스템에는 보통 이 폴더를 포함시키지 않습니다 (.gitignore 파일에 추가). 왜냐하면 package.json 파일만 있으면 언제든지 npm install 명령어로 동일하게 복원할 수 있기 때문입니다.

  • package-lock.json: package.json이 ‘어떤 패키지를 설치할지’에 대한 느슨한 설계도라면, package-lock.json은 ‘정확히 어떤 버전의 패키지를 설치했는지’에 대한 상세한 기록부입니다.

    package.json에는 보통 ^나 ~ 같은 기호가 붙어 버전의 범위를 지정합니다 (“react”: “^18.2.0”는 18.2.0 이상 19.0.0 미만 버전을 의미). 이 때문에 서로 다른 시점에 npm install을 실행하면 설치되는 패키지의 세부 버전이 달라질 수 있습니다. 이는 “내 컴퓨터에서는 잘 됐는데, 왜 네 컴퓨터에서는 안돼?” 문제의 주된 원인이 됩니다.

    package-lock.json은 최초 설치 시점의 모든 패키지(의존성의 의존성까지 포함)의 정확한 버전과 다운로드 주소를 스냅샷처럼 기록하여, 다른 환경에서도 항상 동일한 버전의 패키지들이 설치되도록 보장합니다. 이를 통해 **재현 가능한 빌드(Reproducible Build)**를 가능하게 합니다. 이 파일은 node_modules나 package.json이 변경될 때 자동으로 생성되거나 업데이트되며, 반드시 Git에 포함시켜 팀원 모두가 동일한 의존성 트리를 공유하도록 해야 합니다.

3. 필수 npm 사용법 가이드

이제 이론을 알았으니, 실제로 npm을 어떻게 사용하는지 알아봅시다.

3.1. 프로젝트 시작하기

새로운 프로젝트 폴더를 만들고 터미널에서 다음 명령어를 입력합니다.

Bash

npm init

이 명령어는 package.json 파일을 생성하기 위한 대화형 프롬프트를 시작합니다. 프로젝트 이름, 버전, 설명 등을 순서대로 물어봅니다. 만약 모든 질문에 기본값으로 빠르게 생성하고 싶다면 -y 플래그를 사용합니다.

Bash

npm init -y

3.2. 패키지 설치하기

가장 많이 사용하는 명령어입니다. 웹 서버 프레임워크인 express를 설치해 보겠습니다.

Bash

npm install express

축약형으로 npm i express를 사용할 수도 있습니다. 이 명령어를 실행하면,

  1. express 패키지가 node_modules 폴더에 다운로드됩니다.

  2. package.json 파일의 dependencies 항목에 "express": "^버전"이 추가됩니다.

  3. package-lock.json 파일이 생성되거나 업데이트됩니다.

개발용 의존성(예: nodemon)을 설치하려면 --save-dev 또는 -D 플래그를 사용합니다.

Bash

npm install --save-dev nodemon

3.3. 패키지 삭제 및 업데이트

  • 삭제:

    Bash

    npm uninstall express
    
  • 업데이트: package.json에 명시된 버전 범위 내에서 패키지를 최신 버전으로 업데이트합니다.

    Bash

    npm update
    
  • 구버전 확인: 설치된 패키지 중 업데이트가 가능한 목록을 보여줍니다.

    Bash

    npm outdated
    

3.4. 스크립트 실행하기

package.jsonscripts에 등록된 명령어를 실행할 때는 npm run을 사용합니다.

JSON

// package.json
"scripts": {
  "start": "node index.js",
  "test": "echo \"Error: no test specified\" && exit 1"
}

위와 같이 등록되어 있다면, 터미널에서 다음 명령어로 node index.js를 실행할 수 있습니다.

Bash

npm run start

단, start, test, stop, restart는 특수한 스크립트로, run을 생략하고 npm start처럼 실행할 수 있습니다.

3.5. 전역(Global) 설치와 npx

때로는 특정 패키지를 프로젝트에 종속시키지 않고, 시스템 전반에서 사용할 수 있는 명령줄 도구로 설치하고 싶을 때가 있습니다. 이때는 -g 플래그를 사용합니다.

Bash

npm install -g create-react-app

하지만 전역 설치는 시스템을 지저분하게 만들고 버전 충돌을 일으킬 수 있다는 단점이 있습니다. 이 문제를 해결하기 위해 npx가 등장했습니다.

npx는 패키지를 전역으로 설치하지 않고, 일회성으로 최신 버전의 패키지를 다운로드하여 실행한 뒤 바로 삭제하는 스마트한 도구입니다.

Bash

# create-react-app을 전역 설치 없이 바로 실행하여 새 프로젝트 생성
npx create-react-app my-app

npx 덕분에 우리는 시스템을 깨끗하게 유지하면서 항상 최신 버전의 CLI 도구를 사용할 수 있게 되었습니다.

4. 더 깊이 알아보기

4.1. npm 보안 감사

우리가 사용하는 패키지, 그리고 그 패키지가 의존하는 수많은 하위 패키지들 속에는 알려진 보안 취약점이 존재할 수 있습니다. npm audit 명령어는 내 프로젝트의 의존성 트리를 스캔하여 이러한 취약점을 찾아내고 보고서를 제공합니다.

Bash

npm audit

간단한 취약점은 다음 명령어로 자동으로 수정할 수 있습니다.

Bash

npm audit fix

4.2. npm vs Yarn vs pnpm

npm 외에도 다른 패키지 관리자들이 존재합니다.

  • Yarn: 페이스북이 개발했으며, 초창기 npm의 느린 속도와 package-lock.json의 부재로 인한 문제를 해결하기 위해 등장했습니다. 빠른 속도와 안정적인 버전 관리로 큰 인기를 끌었습니다. 현재는 npm이 Yarn의 장점들을 많이 흡수하여 성능 차이가 줄었습니다.

  • pnpm: 최근 주목받는 패키지 관리자입니다. node_modules의 구조를 혁신적으로 개선하여 디스크 공간을 매우 효율적으로 사용하고 설치 속도가 월등히 빠르다는 장점이 있습니다.

결론: 단순한 도구를 넘어선 생태계의 중심

npm은 단순히 자바스크립트 패키지를 다운로드하는 도구에서 시작했지만, 이제는 현대 웹 개발의 모든 과정을 아우르는 필수적인 플랫폼으로 자리 잡았습니다. 의존성 관리를 자동화하여 ‘의존성 지옥’에서 우리를 구원했고, package.jsonpackage-lock.json을 통해 안정적이고 재현 가능한 개발 환경을 제공합니다.

또한, npm run 스크립트는 프로젝트의 빌드, 테스트, 배포 과정을 표준화했으며, npx는 시스템을 오염시키지 않으면서 개발 도구를 편리하게 사용할 수 있도록 돕습니다.

무엇보다 npm의 가장 큰 가치는 전 세계 개발자들이 자신의 코드를 손쉽게 공유하고 협업할 수 있는 개방적인 생태계를 구축했다는 점입니다. 우리가 상상하는 거의 모든 기능은 이미 누군가 만들어 npm 레지스트리에 올려두었을 가능성이 높습니다. npm은 이 거대한 지식의 바다를 항해하는 데 필요한 나침반이자 튼튼한 배가 되어주고 있습니다. 이 핸드북이 여러분의 npm 항해에 든든한 길잡이가 되기를 바랍니다.

레퍼런스(References)