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