• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1---
2section: configuring-npm
3title: package-locks
4description: An explanation of npm lockfiles
5---
6
7# package-locks(5)
8
9## An explanation of npm lockfiles
10
11### Description
12
13Conceptually, the "input" to [`npm install`](/cli-commands/npm-install) is a [package.json](/configuring-npm/package-json), while its
14"output" is a fully-formed `node_modules` tree: a representation of the
15dependencies you declared. In an ideal world, npm would work like a pure
16function: the same `package.json` should produce the exact same `node_modules`
17tree, any time. In some cases, this is indeed true. But in many others, npm is
18unable to do this. There are multiple reasons for this:
19
20* different versions of npm (or other package managers) may have been used to install a package, each using slightly different installation algorithms.
21
22* a new version of a direct semver-range package may have been published since the last time your packages were installed, and thus a newer version will be used.
23
24* A dependency of one of your dependencies may have published a new version, which will update even if you used pinned dependency specifiers (`1.2.3` instead of `^1.2.3`)
25
26* The registry you installed from is no longer available, or allows mutation of versions (unlike the primary npm registry), and a different version of a package exists under the same version number now.
27
28As an example, consider package A:
29
30```json
31{
32  "name": "A",
33  "version": "0.1.0",
34  "dependencies": {
35    "B": "<0.1.0"
36  }
37}
38```
39
40package B:
41
42```json
43{
44  "name": "B",
45  "version": "0.0.1",
46  "dependencies": {
47    "C": "<0.1.0"
48  }
49}
50```
51
52and package C:
53```json
54{
55  "name": "C",
56  "version": "0.0.1"
57}
58```
59
60If these are the only versions of A, B, and C available in the
61registry, then a normal `npm install A` will install:
62
63```json
64A@0.1.0
65`-- B@0.0.1
66    `-- C@0.0.1
67```
68
69However, if B@0.0.2 is published, then a fresh `npm install A` will
70install:
71
72```bash
73A@0.1.0
74`-- B@0.0.2
75    `-- C@0.0.1
76```
77
78assuming the new version did not modify B's dependencies. Of course,
79the new version of B could include a new version of C and any number
80of new dependencies. If such changes are undesirable, the author of A
81could specify a dependency on B@0.0.1. However, if A's author and B's
82author are not the same person, there's no way for A's author to say
83that he or she does not want to pull in newly published versions of C
84when B hasn't changed at all.
85
86To prevent this potential issue, npm uses [package-lock.json](/configuring-npm/package-lock-json) or, if present, [npm-shrinkwrap.json](/configuring-npm/shrinkwrap-json). These files are called package locks, or lockfiles.
87
88Whenever you run `npm install`, npm generates or updates your package lock,
89which will look something like this:
90
91```json
92{
93  "name": "A",
94  "version": "0.1.0",
95  ...metadata fields...
96  "dependencies": {
97    "B": {
98      "version": "0.0.1",
99      "resolved": "https://registry.npmjs.org/B/-/B-0.0.1.tgz",
100      "integrity": "sha512-DeAdb33F+"
101      "dependencies": {
102        "C": {
103          "version": "git://github.com/org/C.git#5c380ae319fc4efe9e7f2d9c78b0faa588fd99b4"
104        }
105      }
106    }
107  }
108}
109```
110
111This file describes an *exact*, and more importantly *reproducible*
112`node_modules` tree. Once it's present, any future installation will base its
113work off this file, instead of recalculating dependency versions off
114[package.json](/configuring-npm/package-json).
115
116The presence of a package lock changes the installation behavior such that:
117
1181. The module tree described by the package lock is reproduced. This means
119reproducing the structure described in the file, using the specific files
120referenced in "resolved" if available, falling back to normal package resolution
121using "version" if one isn't.
122
1232. The tree is walked and any missing dependencies are installed in the usual
124fashion.
125
126If `preshrinkwrap`, `shrinkwrap` or `postshrinkwrap` are in the `scripts`
127property of the `package.json`, they will be executed in order. `preshrinkwrap`
128and `shrinkwrap` are executed before the shrinkwrap, `postshrinkwrap` is
129executed afterwards. These scripts run for both `package-lock.json` and
130`npm-shrinkwrap.json`. For example to run some postprocessing on the generated
131file:
132
133```json
134  "scripts": {
135    "postshrinkwrap": "json -I -e \"this.myMetadata = $MY_APP_METADATA\""
136  }
137```
138
139#### Using locked packages
140
141Using a locked package is no different than using any package without a package
142lock: any commands that update `node_modules` and/or `package.json`'s
143dependencies will automatically sync the existing lockfile. This includes `npm
144install`, `npm rm`, `npm update`, etc. To prevent this update from happening,
145you can use the `--no-save` option to prevent saving altogether, or
146`--no-shrinkwrap` to allow `package.json` to be updated while leaving
147`package-lock.json` or `npm-shrinkwrap.json` intact.
148
149It is highly recommended you commit the generated package lock to source
150control: this will allow anyone else on your team, your deployments, your
151CI/continuous integration, and anyone else who runs `npm install` in your
152package source to get the exact same dependency tree that you were developing
153on. Additionally, the diffs from these changes are human-readable and will
154inform you of any changes npm has made to your `node_modules`, so you can notice
155if any transitive dependencies were updated, hoisted, etc.
156
157#### Resolving lockfile conflicts
158
159Occasionally, two separate npm install will create package locks that cause
160merge conflicts in source control systems. As of `npm@5.7.0`, these conflicts
161can be resolved by manually fixing any `package.json` conflicts, and then
162running `npm install [--package-lock-only]` again. npm will automatically
163resolve any conflicts for you and write a merged package lock that includes all
164the dependencies from both branches in a reasonable tree. If
165`--package-lock-only` is provided, it will do this without also modifying your
166local `node_modules/`.
167
168To make this process seamless on git, consider installing
169[`npm-merge-driver`](https://npm.im/npm-merge-driver), which will teach git how
170to do this itself without any user interaction. In short: `$ npx
171npm-merge-driver install -g` will let you do this, and even works with
172pre-`npm@5.7.0` versions of npm 5, albeit a bit more noisily. Note that if
173`package.json` itself conflicts, you will have to resolve that by hand and run
174`npm install` manually, even with the merge driver.
175
176### See Also
177
178* https://medium.com/@sdboyer/so-you-want-to-write-a-package-manager-4ae9c17d9527
179* [package.json](/configuring-npm/package-json)
180* [package-lock.json](/configuring-npm/package-lock-json)
181* [shrinkwrap.json](/configuring-npm/shrinkwrap-json)
182* [npm shrinkwrap](/cli-commands/npm-shrinkwrap)
183