If you are a developer who is familiar with JavaScript, I’m sure you know NPM (Node Package Manager). There are some JSON files that are associated with NPM that can be useful in certain scenarios in your JS/TS project. However, most developers have no much idea about these JSON files. So in this article, I’m gonna explain when and why these JSON files are used in your project.

What is package.json?
The most common JSON file that you come across in a JS project is package.json which is used to mention dependencies and their versions. It also contains important meta data of the project like: project name, description, scripts, author, license, repo link, etc. This is an essential file that has all important meta data of the JS project.
This file helps to install the relevant dependencies for your project. When denoting the version of a package, there are few ways you can do that. Normally, when you save a dependency using npm install --save command, the version number will be saved with a caret sign ^. (In previous versions there was a tilde ~). These two signs indicates two different things for NPM when we try to install dependencies.
The tilde ~ sign indicates that the NPM will fetch the latest patch version of the dependency. For instance, let say the version mentioned is ~1.2.1 and the latest patch version available is 1.2.5, so NPM will install the latest patch version. So 1.2.x version will be installed if you’re trying to install dependencies.
On the other hand, the caret ^ sign will install the most recent minor version. For instance, if the mentioned version is ^1.2.1 and there’s a new version 1.3.0, NPM will install that version. So, if there’s a caret sign in front of the version, it will indicate NPM to look for versions similar to 1.x.x and install. In both scenarios, major versions are not installed.
Locking the versions
Although this seems handy, this can cause lot of issues. Sometimes, certain minor version may create build errors. Installing patch versions are fine, but minor version might be problematic. Imagine there’s developer A who started working on a JS project and push the code. After few months, developer B clone the project and install dependencies and try to run or build the project, now they get errors. when developer B ask developer A, developer A will say the classic comment “it works in my machine”. Well, technically yes. The problem might be related to version mismatch in dependencies in developer B’s installation as their might be updated versions of dependencies.
An unorthodox method would be to zip developer A’s node modules folder and send it to developer B to use, which will technically resolve the issue. But, that is not the conventional way. so, how to avoid such issues? You may mention the dependency versions without tilde or caret and lock it to a specific version. But that is not a recommended practice, as it will create vulnerability issues when the project get’s old.
That’s where package-lock.json comes in.
What is package-lock.json?
If you are using NPM version 5.0.0 or latest, when you do an NPM installation, the package-lock.json file will be created automatically. It is quite similar to package.json and as the name suggests, it “locks” the dependency versions of your project. Everytime you install a new dependency, this file will be updated. It will record the exact version of the dependency that you installed. You do not need to change this file manually. It also contains some important meta deta that is required when you are using NPM install, where NPM tries to resolve every time. So this can speedup your installation process.
The most important job it does is, it will lock all the dependency versions to the specific version as you have. It’s like a snapshot of the node modules folder you have. In our previous example, it’s like taking a snapshot of developer A’s node modules folder. So when developer A commit the package-lock.json file, developer B can now install the same node modules as developer A. this will save time and effort for developers who are working on the same project.
When you run NPM install, NPM usually look for package-lock.json file first and try to install dependencies as recorded in it. If there’s no package-lock.json file, NPM will do a fresh install using the dependencies mentioned in package.json. Therefore, committing the package-lock.json file to the repo is recommended.
Read more about package-lock.json here.
What is npm-shrinkwrap.json?
Although npm-shrinkwrap.json and package-lock.json files are identical, there’s a difference as npm-shrinkwrap.json is not generated automatically and this file is publishable. Also this file will record exact versions of all the dependencies, including transitive dependencies. This is ideal for production environments, which will ensure that all dependencies will be the same. This is also ideal for projects with strict dependency versions, like legacy projects.
To generate npm-shrinkwrap.json you need to run below command:
npm shrinkwrap
You need to manually update this file by running the same command.
Read more about npm-shrinkwrap.json here.
How to use package-lock.json and npm-shrinkwrap.json?
Even though both files seemingly serves similar purpose, they have different use cases.
If you need flexibility, and you are doing developing and testing more often, use package-lock.json, as it is more simple.
If you need to maintain the versions manually and strictly, especially in production environment, use npm-shrinkwrap.json which allows you to explicitly lock all the dependency versions.
Hope this article help you to understand the use cases of package.json, package-lock.json and npm-shrinkwrap.json files. Now you have a better idea when, where and how to use these files in your JS/TS project.

