Package.json Vs Package-lock.json Vs Npm-shrinkwrap.json
Tags: npm, package, node, packagejson
Published: 2020-02-16 10:41:10


Hi coders, today I am going to share some facts about package.json , package-lock.json and npm-shrinkwrap.json that I came across while working on my current project.
Package.json
I am sure if you are using npm (Node Package Manager) then you already know about the versioning file i.e. package.json.
It is used to install different open source and other available packages (that is, pre-packaged code modules) in a Node.js project. So I am going to explain the use of it in depth.
It is used for more than dependencies - like defining project properties, description, author & license information, scripts, etc.
It records the minimum version you app needs. If you update the versions of a particular package, the change is not going to be reflected here.
Example:

{
  "name": "generator-venv",
  "version": "2.0.1",
  "description": "a generator to create vue environment ",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "generator",
    "vue",
    "router",
    "vuex",
    "components",
    "yeoman-generator",
    "typescript",
    "webpack",
    "babel"
  ],
  "author": "Hossam Hilal",
  "website": "https://github.com/hossamhilal/",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/hossamhilal/generator-venv"
  },
  "license": "ISC",
  "dependencies": {
    "chalk": "^3.0.0",
    "grunt": "^1.0.4",
    "lodash": "^4.17.15",
    "mkdirp": "^1.0.3",
    "npm": "^6.13.7",
    "yeoman-generator": "^4.5.0",
    "yosay": "^2.0.2"
  },
  "devDependencies": {},
  "files": [
    "app" 
  ]
}

So as you can see in the picture above after every dependency listed under package.json there’s a number something like ^3.0.0 which is the version of that package but before the version, there is ^. So ^ this little guy can be a total destroyer for your project.
^ sign before the version tells npm that if someone clones the project and runs npm install in the directory then install the latest minor version of the package in his node_modules.
So lets say I am having express with ^3.0.0 in package.json and then express team releases version 3.5.2 and now when someone clone my repo and runs npm install in that directory they will get the version 2.24.0 (You can also put ~ instead of ^ it will update to latest patch version)
Difference between tilde (~) and caret (^) in package.json
If you have updated your npm to the latest version and tried installing the package using npm install moment — save you will see the package moment.js get saved in packages.json with a caret(^)prefix and in the previous version it was saved with tilde(~)prefix. You might think what is the difference between these symbols.
The tilde prefix simply indicates that the tilde (~) symbol will match the most recent patch version or the most recent minor version i.e. the middle number. For example, ~1.2.3 will match all 1.2.x versions but it will not match 1.3.0 or 1.3.x versions.
The caret indicates the first number i.e. the most recent major version. An example is in 1.x.x release the caret will update you and it will match with 1.3.0 but not 2.0.0.
However, this can be a huge issue if package developers break any of the functions on the minor version as it can make your application break down.
So npm later released a new file called package-lock.json to avoid such scenarios
Read More about Package.json : here
Package-lock.json
Before we get into the details, if you wish to follow along with your own project there is one thing to check first. If you are not using the current version of npm or it is lower than 5.0.0 you’ll need to update it to 5.x.x or current stable version. Once done, install the packages by running the command:
npm i 
OR
npm install
Once this activity is done, you can see that a new file named “package-lock.json” is automatically created. If you open and read the content of this file you will find dependencies like package.json but with more details.
Below is an example structure of package-lock.json for dependency “babel” like that
{
  "name": "generator-venv",
  "version": "2.1.24",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "@babel/code-frame": {
      "version": "7.8.3",
      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
      "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
      "requires": {
        "@babel/highlight": "^7.8.3"
      }
    },
    "@babel/highlight": {
      "version": "7.8.3",
      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
      "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
      "requires": {
        "chalk": "^2.0.0",
        "esutils": "^2.0.2",
        "js-tokens": "^4.0.0"
      },
      "dependencies": {
        "chalk": {
          "version": "2.4.2",
          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
          "requires": {
            "ansi-styles": "^3.2.1",
            "escape-string-regexp": "^1.0.5",
            "supports-color": "^5.3.0"
          }
        }
      }
    }
}
You can simply ignore this file continue with your work but have you ever wondered about these three points -
Why is package-lock.json created?
What is the purpose or use of package-lock.json?
Why should we commit package-lock.json with our project source code?
Let me offer my understanding and answers to these questions.
Why is package-lock.json created?
When you install any package in your project by executing the command
npm i <package-name> — save
it will install the exact latest version of that package in your project and save the dependency in package.json with a carat (^) sign. Like, if the current version of a package is 5.2.3 then the installed version will be 5.2.3 and the saved dependency will be ^5.2.3. Carat (^) means it will support any higher version with major version 5 like 5.3.1 and so on. Here, package-lock.json is created for locking the dependency with the installed version.
The package-lock.json
is an extremely important file that is there to save you from a lot of boom boom bam bam 🔥 in your repositories.
will simply avoid this general behavior of installing updated minor version so when someone clones your repo and run npm install in their machine. NPM will look into package-lock.json and install exact versions of the package as the owner has installed so it will ignore the ^ and ~ from package.json.
is solely used to lock dependencies to a specific version number.
records the exact version of each installed package which allows you to re-install them. Future installs will be able to build an identical dependency tree.
Also, it contains some other meta information which saves time of fetching that data from npm while you do npm install.
Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.
Provide a facility for users to “time-travel” to previous states of node_modules without having to commit the directory itself.
To facilitate greater visibility of tree changes through readable source control diffs.
And optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.

What is the purpose or use of package-lock.json?
To avoid differences in installed dependencies on different environments and to generate the same results on every environment we should use the package-lock.json file to install dependencies.
Ideally, this file should be on your source control with the package.json file so when you or any other user will clone the project and run the command “npm i”, it will install the exact same version saved in package-lock.json file and you will able to generate the same results as you developed with that particular package.
Why should we commit package-lock.json with our project source code?
During deployment, when you again run “npm i” with the same package.json file without the package-lock.json, the installed package might have a higher version now from what you had intended.
Now, what if you wanted to have that particular version for your dependency during deployment which you used at the time of development. This is the need of creating a package-lock.json file and keeping it with the source code. This file is created with the details of the specific version installed in your project.
Keep locking your dependencies!!
Read More about Package.json : here
Npm-shrinkwrap.json
A publishable lockfile
npm-shrinkwrap.json is a file created by npm-shrinkwrap. It is identical to package-lock.json, with one major caveat: Unlike package-lock.json, npm-shrinkwrap.json may be included when publishing a package.
The recommended use-case for npm-shrinkwrap.json is applications deployed through the publishing process on the registry: for example, daemons and command-line tools intended as global installs or devDependencies. It’s strongly discouraged for library authors to publish this file, since that would prevent end users from having control over transitive dependency updates.
Additionally, if both package-lock.json and npm-shrinkwrap.json are present in a package root, package-lock.json will be ignored in favor of this file.
package-lock.json is never published to npm, whereas npm-shrinkwrap is by default
package-lock.json files that are not in the top-level package are ignored, but shrinkwrap files belonging to dependencies are respected
npm-shrinkwrap.json is backwards-compatible with npm versions 2, 3, and 4, whereas package-lock.json is only recognized by npm 5+
You can convert an existing “ Package-lock.json “ to an “Npm-shrinkwrap.json “ by running:
npm shrinkwrap
Thus:
If you are not publishing your package to npm, the choice between these two files is of little consequence. You may wish to use package-lock.json because it is the default and its name is clearer to npm beginners; alternatively, you may wish to use npm-shrinkwrap.json for backwards compatibility with npm 2-4 if it is difficult for you to ensure everyone on your development team is on npm 5+. (Note that npm 5 was released on 25th May 2017; backwards compatibility will become less and less important the further we get from that date, as most people will eventually upgrade.)
If you are publishing your package to npm, you have a choice between:
using a package-lock.json to record exactly which versions of dependencies you installed, but allowing people installing your package to use any version of the dependencies that is compatible with the version ranges dictated by your package.json, or
using an npm-shrinkwrap.json to guarantee that everyone who installs your package gets exactly the same version of all dependencies
The official view described (very tersely) in the docs is that option 1 should be used for libraries (presumably in order to reduce the amount of package duplication caused when lots of a package’s dependencies all depend on slightly different versions of the same secondary dependency), but that option 2 might be reasonable for executables that are going to be installed globally.


AUTHOR : Hossam Hilal
Frontend Developer & WordPress Backend & UI / UX Designer .