パッケージ管理とは — npm install で何がどこに入るか

この記事は、プログラミングやバイブコーディングをする上で最低限身につけたほうがよい IT の実践的な知識を 1 から身につける「IT 基礎知識講座の一部」です。
npm install react と打つと、my-app に node_modules ができて package.json に 1 行増えます。その 1 行で何が起きているのかを図解でたどります。

この記事は、パッケージ管理を扱います。

npm install のような 1 行で外部のライブラリを名前で取り寄せ、決まった場所に置く仕組みです。

npm install react の 1 行で、何がどこへ置かれるか
npm install reactと打つnpm が配布サイトから取り寄せるnode_modules にフォルダが増えるpackage.json に1 行増えるapp.js は変わらない
左の 1 行から中央の npm へ渡り、右の 2 か所に結果が残ります。自分で書いた app.js は変わりません。

打つのは左の 1 行だけで、増えるのは右の 2 つです。

増えるのは node_modules というフォルダと package.json の 1 行だけで、自分で書いた app.js は 1 文字も変わりません。

パッケージとは — 名前を指定して取り寄せる外部ライブラリ

取り寄せられる形にまとめたものがパッケージ(package。外部ライブラリを、名前を指定して取り寄せられる形にまとめたもの)で、その時点の中身を示す番号がバージョン(version)です。

予約アプリ my-app で日付を見やすく表示したいとき、同じ処理は自分でも書けますが、パッケージとしても配られています。

日付の表示を、自分で書く場合と取り寄せる場合
日付を見やすく表示したい自分で書くパッケージを使う何十行も書き、間違いも自分で直す名前を指定して取り寄せ、1 行で呼び出す同じ表示が画面に出る
上から下へ、2 つに分かれて最後は同じところに集まります。分かれるのは書く量で、出てくる画面は変わりません。

左は書いた行がすべて自分のものになり、右は取り寄せたものを 1 行で呼び出すだけです。

react という 1 つのパッケージに入っているもの
react というパッケージ
名前
  • 取り寄せるときに指定する文字列
  • 配布サイトの中で 1 つに決まる
バージョン
  • 改訂するたびに新しい番号が足される
  • 古い番号のものも残っている
ソースコードのファイル
  • 呼び出すと動くプログラム本体
  • 自分では書き換えない
必要とする他のパッケージの名前
  • react だけでは動かない分がここに並ぶ
  • 取り寄せるときに一緒に付いてくる
外側が react というパッケージ 1 つ。取り寄せるときに指定するのは名前とバージョンで、中のファイルはまとめて付いてきます。

取り寄せるときに指定するのは、いちばん上の名前だけです。

いちばん下の「必要とする他のパッケージの名前」が、あとでフォルダの数を増やします。

パッケージは、名前で取り寄せられる外部ライブラリ

パッケージとは、他の人が書いたプログラムを、名前を付けて配れる形にしたものです。

名前を指定すればその中身を自分のパソコンに持ってこられ、バージョンは同じ名前の中で改訂を見分けるための番号です。

npm install react を打つと、my-app の中に何ができるか

名前を指定して取り寄せるのがパッケージ管理ツール(package manager。パッケージを取り寄せ、決まった場所に置くプログラム)で、JavaScript のものが npm です。

打ち方はターミナルで 1 行だけで、どちらも my-app の中で打つことが前提です。

# my-app のフォルダに移動してから打つ
cd my-app

# react という名前のパッケージを 1 つ取り寄せる
npm install react

# 一覧ファイルに並んでいる名前を、まとめて取り寄せる
npm install

取り寄せたパッケージが入るのがnode_modules(npm が my-app の中に作る、取り寄せたパッケージを置くフォルダ)です。

my-app の中で、自分が書くものと npm が作るもの
my-app(予約アプリのフォルダ)
自分で書くファイル
  • app.js — 予約の処理を書いたソースコード
  • package.json — 取り寄せる名前を並べるファイル
node_modules(npm が作る)
react
  • 取り寄せたパッケージのソースコード
  • 呼び出すのはこの中身
取り寄せたものが必要とするパッケージ
  • 名前ごとにフォルダが 1 つずつできる
  • 必要とするものが無ければ、これは増えない
外側が my-app のフォルダ。上の枠が自分で書くファイル、下の枠が npm が作って npm が書き換えるフォルダです。

自分で書くファイルと、npm が作るフォルダは、同じ my-app の中で分かれています。

同じ 1 行でも、打ち方や名前の間違いで結果は変わります。

打ち込んだ 1 行npm がすることmy-app の中の結果
npm install reactその名前と依存を取り寄せるnode_modules にフォルダが増える
npm installpackage.json の名前をまとめてnode_modules がまるごとできる
npm install reactttt探すが見つからない404 Not Found 何も増えない

3 行目のように打ち間違えた名前が配布サイトに無ければ、何も入りません。

打ち間違えた名前が偶然実在すると別のものが入ってしまうので、名前は公式のページから写します。

1 つ取り寄せると、フォルダがいくつも増える理由
npm install expressexpressexpress が必要とするパッケージそれらが必要とするパッケージさらにその先のパッケージnode_modules に数十のフォルダが並ぶ
上から下へ広がり、最後に 1 つに集まります。取り寄せたものが必要とするもの、そのまた先まで一緒に来ます。react のように必要とするものが無いパッケージでは、フォルダは 1 つのままです。

react が必要とするパッケージ、さらにその先が必要とするパッケージまで一緒に来ます。

この数を自分で調べて 1 つずつ取り寄せずに済むことが、パッケージ管理ツールを使う理由です。

取り寄せるのは 1 つでも、node_modules にできるフォルダは 1 つとは限りません。

配布サイトは、インターネットの向こうにある別のコンピュータです。

取り寄せたパッケージが置かれるのは、my-app フォルダの中の node_modules だけです。

自分が書いた app.js は、その中のパッケージを呼び出して使います。

取り寄せたものは node_modules に入る

取り寄せたものが入るのは、my-app の中にできる node_modules というフォルダです。

自分で書いた app.js は変わらず、フォルダが指定した数より増えるのは、取り寄せたものがさらに必要とするものまで一緒に来るからです。

package.json — 取り寄せたパッケージの名前が並ぶ一覧ファイル

node_modules の中身は npm が作ったもので、自分では書き換えません。

自分が管理するのは、取り寄せた名前が並ぶ 1 つのファイルだけです。

それが一覧ファイル(JavaScript では package.json。そのアプリが動くために要るパッケージの名前を書いておくファイル)で、ここに並ぶ名前 1 つ 1 つを依存(dependency。自分のコードが動くために必要なパッケージ)といいます。

{
  "name": "my-app",
  "dependencies": {
    "react": "^19.0.0",
    "express": "^5.1.0"
  }
}

dependencies の中に並ぶ 2 つが、この my-app の依存です。

右側が取り寄せるバージョンの指定で、数字はこの例のためのもので、実際には取り寄せた時点のものが入ります。

先頭の ^ は「書いてある番号と互換性のある新しいバージョンも許す」という印です。

package.json には、依存のほかにも書いてあるものがあります。

package.json の中に並ぶもの
package.json
name
  • このアプリ自身の名前
  • my-app と書いてある
dependencies
  • 動かすために要るパッケージの名前が並ぶ
  • npm install がここを読む
  • react を取り寄せると 1 行増える
scripts
  • よく打つコマンドに短い名前を付けておく場所
  • npm run start のように呼び出す
外側が package.json というファイル 1 つ。npm install が読むのは、真ん中の dependencies の部分です。

npm install が読むのは、真ん中の dependencies の部分です。

同じ 1 つのものが、どこから見るかで 3 つの呼び名になります。

同じ 1 つのものが、見る場所によって呼び名が変わる
==配布サイトの中パッケージ名前とバージョンを付けて置いてあるpackage.json の中依存my-app が動くために要る名前として並ぶapp.js の中外部ライブラリ呼び出して使うプログラム
左が見ている場所、真ん中がそこでの呼び名、右がその場所での扱われ方。二重線で結んだ 3 つは同じものです。

一覧ファイルがあるおかげで、node_modules を人に渡さずに済みます。

別のパソコンに渡したもの相手が npm install を打つとmy-app は動くか
app.js と package.json一覧の名前をすべて取り寄せる同じものがそろい動く
app.js だけ取り寄せる名前が分からない呼び出しでエラーになる
app.js と node_modules打たなくても中身はある動くが、渡すものが数百になる

渡すのは app.js と package.json で、相手は npm install を 1 回打つだけです。

npm が読むのは package.json の dependencies だけで、そこに並ぶ名前を配布サイトから取り寄せて node_modules を作り直します。

node_modules をそのまま渡す必要はありません。

名前の一覧さえあれば、中身は作り直せる

package.json は、この my-app が動くために要るパッケージの名前を並べたファイルです。

npm install はこのファイルを読んで名前をまとめて取り寄せるので、node_modules はいつでも作り直せ、人に渡す必要もありません。

Python でも同じ — pip と requirements.txt、置き場所を分ける仮想環境

ここまでは JavaScript の名前で見てきました。

Python でも、名前が違うだけで、していることは同じです。

JavaScript と Python で、同じ役割を持つもの
===JavaScriptnpmpackage.jsonnode_modulesPythonpiprequirements.txtsite-packages役割名前を指定して取り寄せる取り寄せる名前を並べておく取り寄せたものが入る場所
上段が JavaScript、中段が Python の名前、下段がその役割。二重線で結んだ 2 つは、名前が違うだけで役割が同じです。

取り寄せるのが pip、名前を並べる一覧ファイルが requirements.txt です。

役割が同じなので、片方を覚えればもう片方も同じように読めます。

1 つだけ違うのが置き場所で、仮想環境を作っていないと pip はパソコン全体に入れようとします。

これを避けるために作るのが仮想環境(virtual environment。そのアプリ専用のパッケージの置き場所を、フォルダとして作る仕組み)です。

アプリごとに分かれる、パッケージの置き場所
自分のパソコン
my-app(予約アプリ)
  • node_modules — この中に依存が入る
  • 別のアプリからは見えない
other-app(別のアプリ)
  • 別の node_modules を持つ
  • 同じ名前の違うバージョンが入ってもぶつからない
仮想環境を作らなかった Python のアプリ
  • site-packages はパソコン全体に 1 つだけ
  • 別のアプリが違うバージョンを要求するとぶつかる
外側が自分のパソコン。上の 2 つはフォルダの中に置き場所があり、いちばん下だけがパソコン全体を 1 つで共有します。

アプリごとにフォルダが分かれていれば、同じ名前の違うバージョンが並んでもぶつかりません。

手順書が最初に仮想環境を作らせるのは、この分かれ目を作るためです。

言語が違っても、3 つの役割は同じ

どの言語にも、取り寄せるプログラムと、名前を並べる一覧ファイルと、入ったものの置き場所があります。

JavaScript では npm と package.json と node_modules、Python では pip と requirements.txt で、Python だけは仮想環境を作らないと置き場所がパソコン全体になります。

QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1my-app のフォルダで npm install react を打ったとき、取り寄せたパッケージが入るのはどこですか。

Q2別のパソコンで同じ my-app を動かすとき、node_modules を渡さずに済むのはなぜですか。

Q3パッケージを 1 つ取り寄せただけで、node_modules のフォルダがそれより増えることがあるのはなぜですか。