1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
|
.\" Generated with Ronnjs 0.3.8
.\" http://github.com/kapouer/ronnjs/
.
.TH "NPM\-SHRINKWRAP" "1" "February 2013" "" ""
.
.SH "NAME"
\fBnpm-shrinkwrap\fR \-\- Lock down dependency versions
.
.SH "SYNOPSIS"
.
.nf
npm shrinkwrap
.
.fi
.
.SH "DESCRIPTION"
This command locks down the versions of a package\'s dependencies so that you can
control exactly which versions of each dependency will be used when your package
is installed\.
.
.P
By default, "npm install" recursively installs the target\'s dependencies (as
specified in package\.json), choosing the latest available version that satisfies
the dependency\'s semver pattern\. In some situations, particularly when shipping
software where each change is tightly managed, it\'s desirable to fully specify
each version of each dependency recursively so that subsequent builds and
deploys do not inadvertently pick up newer versions of a dependency that satisfy
the semver pattern\. Specifying specific semver patterns in each dependency\'s
package\.json would facilitate this, but that\'s not always possible or desirable,
as when another author owns the npm package\. It\'s also possible to check
dependencies directly into source control, but that may be undesirable for other
reasons\.
.
.P
As an example, consider package A:
.
.IP "" 4
.
.nf
{
"name": "A",
"version": "0\.1\.0",
"dependencies": {
"B": "<0\.1\.0"
}
}
.
.fi
.
.IP "" 0
.
.P
package B:
.
.IP "" 4
.
.nf
{
"name": "B",
"version": "0\.0\.1",
"dependencies": {
"C": "<0\.1\.0"
}
}
.
.fi
.
.IP "" 0
.
.P
and package C:
.
.IP "" 4
.
.nf
{
"name": "C,
"version": "0\.0\.1"
}
.
.fi
.
.IP "" 0
.
.P
If these are the only versions of A, B, and C available in the registry, then
a normal "npm install A" will install:
.
.IP "" 4
.
.nf
A@0\.1\.0
`\-\- B@0\.0\.1
`\-\- C@0\.0\.1
.
.fi
.
.IP "" 0
.
.P
However, if B@0\.0\.2 is published, then a fresh "npm install A" will install:
.
.IP "" 4
.
.nf
A@0\.1\.0
`\-\- B@0\.0\.2
`\-\- C@0\.0\.1
.
.fi
.
.IP "" 0
.
.P
assuming the new version did not modify B\'s dependencies\. Of course, the new
version of B could include a new version of C and any number of new
dependencies\. If such changes are undesirable, the author of A could specify a
dependency on B@0\.0\.1\. However, if A\'s author and B\'s author are not the same
person, there\'s no way for A\'s author to say that he or she does not want to
pull in newly published versions of C when B hasn\'t changed at all\.
.
.P
In this case, A\'s author can run
.
.IP "" 4
.
.nf
npm shrinkwrap
.
.fi
.
.IP "" 0
.
.P
This generates npm\-shrinkwrap\.json, which will look something like this:
.
.IP "" 4
.
.nf
{
"name": "A",
"version": "0\.1\.0",
"dependencies": {
"B": {
"version": "0\.0\.1",
"dependencies": {
"C": {
"version": "0\.1\.0"
}
}
}
}
}
.
.fi
.
.IP "" 0
.
.P
The shrinkwrap command has locked down the dependencies based on what\'s
currently installed in node_modules\. When "npm install" installs a package with
a npm\-shrinkwrap\.json file in the package root, the shrinkwrap file (rather than
package\.json files) completely drives the installation of that package and all
of its dependencies (recursively)\. So now the author publishes A@0\.1\.0, and
subsequent installs of this package will use B@0\.0\.1 and C@0\.1\.0, regardless the
dependencies and versions listed in A\'s, B\'s, and C\'s package\.json files\.
.
.SS "Using shrinkwrapped packages"
Using a shrinkwrapped package is no different than using any other package: you
can "npm install" it by hand, or add a dependency to your package\.json file and
"npm install" it\.
.
.SS "Building shrinkwrapped packages"
To shrinkwrap an existing package:
.
.IP "1" 4
Run "npm install" in the package root to install the current versions of all
dependencies\.
.
.IP "2" 4
Validate that the package works as expected with these versions\.
.
.IP "3" 4
Run "npm shrinkwrap", add npm\-shrinkwrap\.json to git, and publish your
package\.
.
.IP "" 0
.
.P
To add or update a dependency in a shrinkwrapped package:
.
.IP "1" 4
Run "npm install" in the package root to install the current versions of all
dependencies\.
.
.IP "2" 4
Add or update dependencies\. "npm install" each new or updated package
individually and then update package\.json\. Note that they must be
explicitly named in order to be installed: running \fBnpm install\fR with
no arguments will merely reproduce the existing shrinkwrap\.
.
.IP "3" 4
Validate that the package works as expected with the new dependencies\.
.
.IP "4" 4
Run "npm shrinkwrap", commit the new npm\-shrinkwrap\.json, and publish your
package\.
.
.IP "" 0
.
.P
You can use npm help outdated to view dependencies with newer versions available\.
.
.SS "Other Notes"
Since "npm shrinkwrap" uses the locally installed packages to construct the
shrinkwrap file, devDependencies will be included if and only if you\'ve
installed them already when you make the shrinkwrap\.
.
.P
A shrinkwrap file must be consistent with the package\'s package\.json file\. "npm
shrinkwrap" will fail if required dependencies are not already installed, since
that would result in a shrinkwrap that wouldn\'t actually work\. Similarly, the
command will fail if there are extraneous packages (not referenced by
package\.json), since that would indicate that package\.json is not correct\.
.
.P
If shrinkwrapped package A depends on shrinkwrapped package B, B\'s shrinkwrap
will not be used as part of the installation of A\. However, because A\'s
shrinkwrap is constructed from a valid installation of B and recursively
specifies all dependencies, the contents of B\'s shrinkwrap will implicitly be
included in A\'s shrinkwrap\.
.
.SS "Caveats"
Shrinkwrap files only lock down package versions, not actual package contents\.
While discouraged, a package author can republish an existing version of a
package, causing shrinkwrapped packages using that version to pick up different
code than they were before\. If you want to avoid any risk that a byzantine
author replaces a package you\'re using with code that breaks your application,
you could modify the shrinkwrap file to use git URL references rather than
version numbers so that npm always fetches all packages from git\.
.
.P
If you wish to lock down the specific bytes included in a package, for
example to have 100% confidence in being able to reproduce a deployment
or build, then you ought to check your dependencies into source control,
or pursue some other mechanism that can verify contents rather than
versions\.
.
.SH "SEE ALSO"
.
.IP "\(bu" 4
npm help install
.
.IP "\(bu" 4
npm help json
.
.IP "\(bu" 4
npm help list
.
.IP "" 0
|