62

Just updated from npm 3 to 5, to use this feature.

Sorry, I must be missing something totally obvious, but how do make npm respect the pinned versions in package-lock.json file when installing?

Let's say I have a package.json with a fair bit of outdated packages. Doing an npm install will pull in new stuff and breaks my app.

For example, the main package I want to stabilize is bootstrap - I want to block its version at bootstrap@4.0.0-alpha.6 for now, but npm install finds 4.0.0-beta.28.

If I npm update any package, package-lock.json gets updated.

Let's go to my development directory.

This is my package.json entry for bootstrap:

"bootstrap": "^4.0.0-alpha.6"

And this is what I see for my installed packages and meta data:

$ npm list 2>/dev/null | grep bootstrap
├─┬ bootstrap@4.0.0-alpha.6
├─┬ bootstrap-vue@0.16.1
│ ├── bootstrap@4.0.0-alpha.6 deduped


(env) jluc@py$ grep bootstrap package.json package-lock.json
package.json:    "bootstrap": "^4.0.0-alpha.6",
package.json:    "bootstrap-vue": "^0.16.1",
package-lock.json:    "bootstrap": {
package-lock.json:      "version": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz",
package-lock.json:    "bootstrap-vue": {
package-lock.json:      "version": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-0.16.1.tgz",
package-lock.json:        "bootstrap": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz",

Looks good. Lock is bootstrap-4.0.0-alpha.6.

But how I use actually use that package-lock.json?

Here's what I did:

  • created a brand new directory
  • copied in package.json and package-lock.json
  • ran npm install.

No good. npm again found bootstrap beta and package-lock.json had no effect, in fact it was rewritten from what npm install did. Which is consistent with the behavior you want in dev, but doesn't tell me how I would use the lockfile to stabilize my packages.

(env) jluc@trynpmlock$ npm list 2>/dev/null | grep bootstrap
├── bootstrap@4.0.0-beta.2
├─┬ bootstrap-vue@0.16.1
│ ├── bootstrap@4.0.0-beta.2 deduped

(env) jluc@trynpmlock$ grep bootstrap package.json package-lock.json
package.json:    "bootstrap": "^4.0.0-alpha.6",
package.json:    "bootstrap-vue": "^0.16.1",
package-lock.json:    "bootstrap": {
package-lock.json:      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-beta.2.tgz",
package-lock.json:    "bootstrap-vue": {
package-lock.json:      "resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-0.16.1.tgz",
package-lock.json:        "bootstrap": "4.0.0-beta.2",
  • If I delete the package.json and only have a directory with package-lock.json, then npm install installs very little and leaves me with a truncated package-lock.json

  • npm install has a --no-package-lock option, but that prevents updating the package-lock.json.

Basically how do I tell npm install everything from package.json, but respect locks in package-lock.json? Do I use a different command than npm install? Is it because npm install's doc refers to locks in the context of a package installation, but locks don't apply when you install the package.json in its entirety?

Yes, I know I can specify "bootstrap": "4.0.0-alpha.6", minus the ^, to pin the version manually.

My environment:

(env) jluc@py$ npm -v
5.5.1
Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
JL Peyret
  • 10,917
  • 2
  • 54
  • 73
  • 1
    Does this answer your question? [Why does "npm install" rewrite package-lock.json?](https://stackoverflow.com/questions/45022048/why-does-npm-install-rewrite-package-lock-json) – ford04 May 22 '20 at 06:18
  • 2
    @ford04 not really, no. I was concerned here with the end result, getting npm to respect the locks, not so much with `npm install`s specific behavior. Notice how the title is phrased. Plus, when I wrote this question, there was no `npm ci` mentioned in the linked question's accepted answer so it did not answer my question at the time (I might even have looked it over then). Seems to me there is no great harm in leaving another breadcrumb question to find `npm ci`, unless the npm doc about locks has become strikingly limpid and clear. – JL Peyret May 22 '20 at 18:37
  • Yet another `npm ci` related answer: https://stackoverflow.com/a/64014814/10788155 – Ictus Aug 21 '22 at 14:08

3 Answers3

62

You need to use the npm ci command to install from package-lock.json.

See: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable

Dave Potts
  • 1,543
  • 2
  • 22
  • 33
  • 1
    This is interesting. Busy with somethinh else but will defintitely check it out. Makes sense that theyd have something, just wish it had been clearer. – JL Peyret Feb 08 '19 at 00:33
  • 5
    This fails if I don't have a package.json file... `ENOENT: no such file or directory, open '/home/chris/fuck3/package.json'` – Chris Stryczynski Jul 11 '19 at 17:29
  • 2
    I've switched this over to be accepted, because it seems to do pretty much what I was asking for, even if @Volti s answer was correct at the time - this command came after. – JL Peyret Jul 17 '19 at 01:22
  • 1
    When running `npm ci` you need to be sure that you have both `package.json` file and `package-lock.json`. – abautista Sep 04 '19 at 15:51
26

Update: As Dave pointed out, the command for this situation is now npm ci. It will install from package-lock.json and will not update it. See the documentation for more information.


According to this comment by a member of the npm CLI team, what you are describing is a "high priority bug".

  1. If you have a package.json and you run npm i we generate a package-lock.json from it.

  2. If you run npm i against that package.json and package-lock.json, the latter will never be updated, even if the package.json would be happy with newer versions.

  3. If you manually edit your package.json to have different ranges and run npm i and those ranges aren't compatible with your package-lock.json then the latter will be updated with version that are compatible with your package.json. Further runs of npm i will be as with 2 above.

If you do run into a case where npm@^5.4.2 mutates a package-lock.json that was otherwise compatible with the paired package.json please open a new issue. This sort of thing would constitute a high priority bug.

Lea Reimann
  • 64
  • 2
  • 7
Jason Schindler
  • 2,790
  • 1
  • 13
  • 8
  • 10
    So, then, if I understand you correctly, your position is that **package-lock.json** does NOT, in fact, provide the services it is expected, and advertised to do? I.e. it can't be relied upon to install based on the exact versions that were saved in it the last time it was updated (if that is the case, what does this feature provide besides promoting false expectations????). One reason for my confusion is all these questions seem to get lumped into *why does package.json get rewritten?*. That's not the real issue - the real issue is *why is it not **used** *. – JL Peyret Dec 04 '17 at 19:44
  • If you rephrase your answer to specify that lock can't be used to install from it (a quote from an authoritative person in the github issue would be nice if you can get it) - I am inclined to grant you the bounty. My one worry is a) if you're wrong - after all this goes against any reasonable expectations and b) if that situation changes. So, I'd in any case wait till the last minute for rebuttals and I'd want to remove this answer if this behiavor gets fixed. Fair? Don't care that much about cipm, core npm behavior is what I care about. – JL Peyret Dec 04 '17 at 19:49
  • I kinda hope I am wrong ;-) I'm with you, lets get to the bottom of this. – Jason Schindler Dec 04 '17 at 21:06
  • I re-read your question and realized that you weren't changing the package.json in the process... my apologies. According to the same GitHub issue thread, that behavior is a bug. – Jason Schindler Dec 04 '17 at 23:45
  • alright accepted. if it turns out to be the wrong answer, I am totally open to revisiting this to avoid confusion. but for now it seems that **package-lock.json**, by itself, does not enforce stability. – JL Peyret Dec 04 '17 at 23:45
  • so, package-lock.json should work??? how? I've only really seen the `npm install` side of things document, which, to my understanding reads **package.json** and updates **package-lock.json**. I haven't seen anywhere yet how package-lock.json gets **used**, rather than **written to**. – JL Peyret Dec 04 '17 at 23:53
  • According to what I've read, if you don't actually edit package.json, package-lock.json shouldn't be updated assuming you are using an NPM version 5.4.2 or better. Since you said you are using 5.5.1 and you aren't changing your package.json file, I think you have a bug... – Jason Schindler Dec 05 '17 at 00:02
  • hmmm. so how would you test expected behavior? I am thinking: 1. `npm install` 2 _outdated_ packages (by specifiying versions). 2. `npm update` one of them. that leaves package-lock version alone for the other. 3. copy package.json and package-lock.json to a new directory. 4. `npm install` - from what you said, I should have the updated package to latest version but the other obsolete package should have been fetched as per the package-lock which is the old version. Am I understanding the intent correctly? I might need to unpin versions after the first install. – JL Peyret Dec 05 '17 at 01:44
  • all in all, I am finding it very hard to believe I am hitting a bug on such a high profile feature, as opposed to not using npm correctly. – JL Peyret Dec 05 '17 at 01:48
  • Wonder if/how we could switch to Dave Potts’s answer? Looks like it solves the question, I’ve already successfully written it into my own Ansible configs. Do you think it works? My understanding is that your bounty’s yours by now, as it should be. – JL Peyret Jun 05 '19 at 05:39
  • hey, sorry, just realized I didn't DM you on my last comment. What do you think of switching over? From this, it seems to be an npm 5.7.1+ thingy: https://stackoverflow.com/questions/52499617/what-is-the-difference-between-npm-install-and-npm-ci – JL Peyret Jun 21 '19 at 02:52
  • 1
    I changed this one as well. When I answered this originally, `npm ci` wasn't a thing. It was added in 5.7. Feel free to switch the accepted answer to his. Either way, `npm ci` solves the issues you were having. – Jason Schindler Jun 26 '19 at 11:38
0

This also seems to work

npm i --save-exact

~ https://docs.npmjs.com/cli/v7/commands/npm-install

Justin
  • 21
  • 2