I am learning about the differences between package.json
and package-lock.json
I been experimenting on a package with only one dependency called chance
I first installed it via npm i [email protected]
and the package.json
has "chance": "^1.0.0"
and package-lock.json
has "version": "1.0.0"
.
Because I wanted to see the effect that the lock file has on the version, I went ahead and deleted package-lock.json
and node_modules
, I ran npm install
, the version of chance
stays the same in package.json
, which is "chance": "^1.0.0"
. In the newly created lock file, the version of chance
became "chance": {"version": "1.1.8",
, so it updated itself.
I then deleted package-lock.json
and node_modules
again and ran npm update
, the results seemed to be the same with the previous experiment – in package.json
I have "^1.0.0"
in package.json
and "1.1.8"
in package-lock.json
My questions are:
- in either case, with
"^1.0.0"
inpackage.json
and"1.1.8"
inpackage-lock.json
, which version of the dependency am I actually using in my project, I guess it is1.1.8
right? so by merely looking at the versions inpackage.json
is not enough to determine the exact version of the dependencies used in a project? - When does running
npm install
change the lock file? I know that if we delete the lock file, it will generate a new one with the newest versions in the allowable ranges frompackage.json
. But are there any cases wherenpm install
would change the lock file even if I didn't delete the lock file?
So, the answer is a bit complex. Essentially there are 2 things at play: The version of the package you want/need, and the version of the package that is installed.
When you are building a project, you probably don't care what specific version of a given dependency is. Most of the time you want the latest one, or the latest patch near a specific major version. The package.json is supposed to document what you, the developer, believe is required for your project to work. So, if you put in the package json
"chance": "1.0.0"
, it would mean that only version1.0.0
exactly is acceptable, and any other version is unacceptable. If you put"chance": "^1.0.0"
, it means any version compatible with1.0.0
is acceptable. So1.2
or1.3
might also be fine, but 1.4 might introduce a change that breaks compatibility.Once you decide what packages you want, by writing the package json, you run
npm install
.npm install
can't always install exactly the versions you want. For example, imagine you want to install two packages: React v1.13 and momentJS v2.8. So you add these to your package json like this:(Note: these version numbers and dependancies are not based on real React or Moment version numbers)
then you run
npm install
. And you get an error:Package dependencies cannot be resolved.
(or something like that). The problem is that React version 1.13 requires momentJS 2.9, but your package json specifies that you want version 2.8 exactly. You can't have both, so npm isn't able to resolve the conflict. A fix would be:Now you are saying that you need a version of moment compatible with 2.8, and you are okay with npm adjusting that to satisfy other packages. Run npm install again and npm might install version 2.9, which satisfies both your requirement of "compatible with 1.8" and React, which wants 2.9. Now, the web app I'm currently working on has over 1,000 dependancies total, so npm absolutely needs to be able to adjust version numbers in order to get all of those packages to play nice.
Now there is often more than one way to solve a dependancy graph--more than one way to adjust all the version numbers to make every package happy. Your package lock file records what the current solution is and what actual packages are installed.
All the options for specifying package verions are here
Hope that helps!
Also: the second part of your question was "will npm change the lock file without me deleting it?" And the answer is: basically everytime you run npm install, npm changes the lock file. What npm does try to do is change the lock file as little as possible with each new install and keep most packages the same