package.json と package-lock.json の違いを言語化できるようにざっくり記事にしてみた
いつも業務でお世話になっている
package.json と package-lock.jsonですが、
詳細部分(バージョン範囲指定)などを言語化がすっとできなかったので、
記事にしておきたいと思います。
この記事で学べること
package.json と package-lock.json の違い
レストランで例えて解説
-
package.json = メニュー
「パスタください」「肉料理ください」(ざっくり注文)
→ 手書きで作るメニュー
→ バージョン範囲(^ や ~)で「どのくらい新しいものでもOKか」を指定できる -
package-lock.json = 詳細なレシピ
「ボロネーゼパスタ、トマト缶2個、牛ひき肉200g、玉ねぎ1個…」(具体的な材料リスト)
→ 実際にパッケージをインストール・更新したときに パッケージマネージャー(npm / yarn / pnpm)が自動で生成・更新するファイル
→ 実際にインストールされた正確なバージョンを固定
バージョン指定の意味
記号 | 例 | 意味 |
---|---|---|
^ |
"^18.0.0" |
メジャーが同じ範囲で最新バージョンまでOK(18.x.x) |
~ |
"~18.0.0" |
マイナーが同じ範囲で最新バージョンまでOK(18.0.x) |
なし | "18.0.0" |
ちょうどそのバージョンのみ |
実際のファイル例
package.json(メニュー)
{
"dependencies": {
"react": "^18.0.0", // メジャー18系なら最新までOK
"react-dom": "~18.0.0", // マイナー18.0.xのみOK
"axios": "0.27.2" // 完全固定
}
}
package-lock.json(レシピ)
{
"packages": {
"react": {
"version": "18.2.0"
},
"react-dom": {
"version": "18.0.1"
},
"axios": {
"version": "0.27.2"
}
}
}
package.json → package-lock.json → node_modules の流れ(Mermaid図)
なぜ両方必要?
問題:
同じメニューでも、シェフによって違う料理が出てくる
- 開発者A: 「React」→ 18.0.0
- 開発者B: 「React」→ 18.2.0(新しいバージョン)
解決:
レシピがあれば全員同じ料理
→ 「React 18.2.0」を固定
結果: 全員が同じReactバージョンで開発できる ✅
類似の考え方が適用できるエコシステム
言語 / エコシステム | ファイル例 | 説明 |
---|---|---|
JavaScript / Node.js | package.json | 依存パッケージの名前とバージョン範囲を宣言 |
JavaScript / Node.js (Yarn) | yarn.lock 併用 | Yarn用のロックファイル |
PHP / Composer | composer.json | 依存パッケージを宣言 |
考え方はほぼ同じです。package.jsonで「何を使うか」を決め、lock系ファイルで「実際にどのバージョンで固定するか」を管理するイメージ。
まとめ
- package.json = 「何が欲しいか」のリスト(バージョン範囲指定)
- package-lock.json = 「実際に何を使ったか」の記録(完全固定)
- 両方必要 = チーム全員が同じ環境で開発できる 🤝
覚え方:
メニューとレシピの関係
実務での注意点
- lockファイルはチーム全員で共有する(gitでコミット)
- package.jsonのバージョン範囲とlockファイルのバージョン差分に注意
- パッケージ更新時は、
npm install
/yarn install
で lock ファイルが自動更新される - 不要な差分やコンフリクトが出る場合は、
rm -rf node_modules && npm install
で整理
lockファイルとpackage.jsonをセットで確認する習慣をつけると、依存関係トラブルを未然に防げます。