Reputation: 46267
npm 5 was released today and one of the new features include deterministic installs with the creation of a package-lock.json
file.
Is this file supposed to be kept in source control?
I'm assuming it's similar to yarn.lock
and composer.lock
, both of which are supposed to be kept in source control.
Upvotes: 2517
Views: 1131902
Reputation: 13156
Yes, it's intended to be checked in. I want to suggest that it gets its own unique commit. We find that it adds a lot of noise to our diffs.
Update: Github handles package-lock.json and similar files better now, and will minimize them by default.
Upvotes: 144
Reputation: 1941
As of April 2023, my answer is:
OF COURSE YOU MUST COMMIT THIS FILE
For instance, standard install command on CI platforms would be
npm ci
npm ci
needs that file to work properly to ENSURE the dependency tree is the exact same as commited.
My old answer is both outdated (2018) and lacks knowledge. It was:
I don't commit this file in my projects. What's the point ?
Though it's true that I never use ^ in my package.json for libs because I had bad experiences with it.
Upvotes: 61
Reputation: 11027
TLDR
Commit in these situations:
npm/yarn
packages to project.package.json
updates the .lock
file..lock
file.Do not commit in these situations:
it means another dev did not push their lock file during the above cases 1,2,3
it means another dev did not push their lock file during the above cases 1,2,3
it means another dev did not push their lock file during the above cases 1,2,3
it means another dev did not push their lock file during the above cases 1,2,3
The main goal of a lock file is that
all developers
& all environments
& all machines
on which the project is installed should have ULTRA ACCURATE libraries & versions
so basically, there are only 3 situations for committing.
Upvotes: 4
Reputation: 13223
All responses are affirmative; however, this varies according to the type of project, according to the documentation.
One key detail about
package-lock.json
is that it cannot be published, and it will be ignored if found in any place other than the toplevel package.
Source: https://docs.npmjs.com/cli/v6/configuring-npm/package-lock-json
This means that you don't need to publish your package-lock.json
to npm for dependencies, but you should use package-lock.json
in your repository to lock the versions of your test dependencies, build dependencies, and so on.
However, if you are using lerna to manage projects with multiple packages, you should place the package-lock.json
only at the root of your repository, not in each subpackage created with npm init
. You will end up with something like this:
.git
lerna.json
package.json
package-lock.json <--- here
packages/a/package.json
packages/a/lib/index.js
packages/b/package.json
packages/b/lib/index.js
Upvotes: 7
Reputation: 6520
Bit background about why to commit package-lock.json
Why not just keep exact versions in package.json?
Your package.json only points to the versions of your direct dependencies. If they have dependencies too (and they do), these versions won't be locked.
Why not delete package-lock.json?
Think about it, if you delete package-lock and re-install, you are forcing the latest versions of all packages in the dependency tree. Meaning, you are changing the behavior of (potentially) the entire application.
What are you really trying to do? If you have some weird npm-related problem, simply remove node_modules and run npm install again. Removing package-lock.json is never the solution.
Why commit package-lock.json? If you don't commit it, then the version of the application everyone else will get is different than what you are running locally. This means that things might work for you, but break on the CI/production/other local machines
Hope it helps to understand.
Upvotes: 2
Reputation: 678
Yes you should commit it, because it holds information about what got installed and this information can be useful — for example, you can make use of it in CI/CD pipelines via executing npm ci
in them in order achieve deterministic builds or when another developer wants to exactly install the same dependencies what you have installed via npm ci
.
Upvotes: 2
Reputation: 15465
The answer is yes, absolutely always commit your lockfile to git.
If you use git, you should use a lockfile because they serve the same purpose:
Because...
Package manager vendors clearly say you should commit the lockfile.
It is highly recommended you commit the generated package lock to source control ...
https://docs.npmjs.com/cli/v6/configuring-npm/package-locks
When npm
installs without a lockfile, it tells you clearly to commit the lockfile:
npm notice created a lockfile as package-lock.json. You should commit this file.
Lockfiles should be committed on all projects
https://classic.yarnpkg.com/blog/2016/11/24/lockfiles-for-all/
You should always commit the lockfile (
pnpm-lock.yaml
).
A single commit should be the same forever, and its build output should not change over time.
From npm:
[a lockfile] will allow anyone else on your team, your deployments, your CI/continuous integration, and anyone else who runs npm install in your package source to get the exact same dependency tree that you were developing on.
From yarn:
If you don’t store which version you ended up installing, someone could be installing the same set of dependencies and end up with different versions depending on when they installed. This can lead to “Works On My Machine” problems and should be avoided.
When something changes, you want git to track that change.
From npm:
[with a lockfile] the diffs from [installation] changes are human-readable and will inform you of any changes npm has made to your
node_modules
, so you can notice if any transitive dependencies were updated, hoisted, etc.
Avoid introducing bugs and vulnerabilities.
From yarn:
Since package authors are people and they can make mistake, it’s possible for them to publish an accidental breaking change in a minor or patch version. If you install this breaking change when you don’t intend to it could have bad consequences like breaking your app in production.
If the package author is either malicious or is attacked by someone malicious and a bad version is published, you do not want that code to end up running without you knowing about it.
This is an "Argument from Ignorance" which is a logical fallacy. In other words, "I don't know the reason, so there is none".
If this file is autogenerated, they why should we commit it? Why can't npm generate it again according to my package.json.
Response: being generated is not a flaw. Git commit hashes are generated; should we not use git? The truth is that the lockfile is not deterministically generated from package.json, because it is susceptible to time and the state of packages in the npm registry. It is a snapshot, for stability.
It's a burden to resolve merge conflicts in checked-in lockfiles.
From npm:
As of
[email protected]
, these conflicts can be resolved by manually fixing anypackage.json
conflicts, and then runningnpm install [--package-lock-only]
again.
From yarn:
when there’s a merge conflict in the lockfile, Yarn will automatically handle the conflict resolution for you upon running
yarn install
.
https://engineering.fb.com/2017/09/07/web/announcing-yarn-1-0/
From pnpm:
pnpm can automatically resolve merge conflicts in
pnpm-lock.yaml
. If you have conflicts, just runpnpm install
and commit the changes.
So all package managers resolve lockfile merge conflicts automatically. This may not be the case in older versions, but it is the case now.
The only time this fails is if the package.json
itself has conflicts, because you can't install from an invalid package.json
. You must resolve those conflicts manually as you would have to do anyway.
Using lock files greatly increases the chance that merging one PR will result in a second PR becoming conflicted with the base branch.
https://docs.renovatebot.com/noise-reduction/#lock-file-considerations
This is true. Git providers (GitHub, GitLab, etc) don't automatically resolve lockfile conflicts, so this may add a burden to merging. However when weighing this con, understand that lockfiles do not normally change; they only change when package.json
deps change, or when a developer specifically changes the file or the installed node_modules
deps.
If diff tools show lockfile diffs, it's a lot of noise.
This is true, however it's a tooling problem which many tools can handle gracefully (such as auto-minimizing, paging, or virtual scrolling). If you don't want to see the lockfile diff at all, try git diff -- . ':(exclude)yarn.lock'
, or alternatively mark the file as binary in .gitattributes
(however you won't see its diff, if that matters to you).
Why not just hardcode dependency version by getting rid of carets and tildes (^ and ~)?
The idea is that not using ranges in your package.json
's dependency semver expressions accomplishes the same thing as having a lockfile.
This is false. Even if you specify exact versions, your dependencies have their own dependencies, which may use ranges for their versions, not exact versions. So this doesn't end up locking the whole dependency tree, only the top of it.
Examples of this objection:
The sentiment is that libraries need to react to bleeding edge deps, and that not having lockfiles supports this.
From yarn:
Some have wondered why libraries should use lockfiles at all ... that using lockfiles when developing libraries creates a false sense of security since your users could be installing different versions than you.
This seems to logically makes sense, but let’s dive deeper into the problem.
The yarn article goes into depth to dispel this objection. Please read it.
A common error in this argument is the thought that if you don't commit the lockfile, it doesn't exist. In reality, it's still there on your machine, locking your dependencies. The situation is not improved by gitignoring the lockfile.
If a library maintainer wishes to continually test for compatibility, then they should delete their lockfile (whether the lockfile is checked in or not!) before installing and building their library. The only difference with a checked-in lockfile is that you have a persistent record of the state of node_modules when this happened, so it can be reproduced in the future.
There are bots like greenkeeper and renovate-bot for this. Greenkeeper advocates for checking in lockfiles (Greenkeeper and Lockfiles: A match made in heaven) and renovate-bot expresses no opinion but does commit lockfiles if present.
This is a claim mentioned (e.g. here): that different OSes generate different lockfile contents. If this is the case, this is a bug.
However it is possible that different versions of npm
(or any package manager) may produce different lockfile output. I have not confirmed this, but hypothetically if so, it is a small price to pay for stability. To workaround this, contributors will need to switch their package manager version, by using a tool like nvm.
See Snyk - Why npm lockfiles can be a security blindspot for injecting malicious modules
This is a real risk. A public project with a lockfile can receive a malicious PR with lockfile contents that could compromise a maintainer's machine once the branch is pulled and installed.
Defend against this with CI checks like lockfile-lint or simply npm ci
or yarn --immutable
(yarn --frozen-lockfile
on Yarn 1), and perhaps setting ignore-scripts
locally in your npmrc
.
This risk is present whenever you install a package with untrusted code.
Always commit the lockfile.
Upvotes: 23
Reputation: 36600
Yes, the best practice is to check-in (YES, CHECK-IN)
I agree that it will cause a lot of noise or conflict when seeing the diff. But the benefits are:
^1.2.3
in your package.json
, but how can you ensure each time npm install
will pick up the same version in your dev machine and in the build server, especially those indirect dependency packages? Well, package-lock.json
will ensure that. (With the help of npm ci
which installs packages based on lock file)npm audit fix
.Upvotes: 120
Reputation: 28046
Yes, package-lock.json
is intended to be checked into source control. If you're using npm 5+, you may see this notice on the command line: created a lockfile as package-lock.json. You should commit this file.
According to npm help package-lock.json
:
package-lock.json
is automatically generated for any operations where npm modifies either thenode_modules
tree, orpackage.json
. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.This file is intended to be committed into source repositories, and serves various purposes:
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.
One key detail about
package-lock.json
is that it cannot be published, and it will be ignored if found in any place other than the toplevel package. It shares a format with npm-shrinkwrap.json, which is essentially the same file, but allows publication. This is not recommended unless deploying a CLI tool or otherwise using the publication process for producing production packages.If both
package-lock.json
andnpm-shrinkwrap.json
are present in the root of a package,package-lock.json
will be completely ignored.
Upvotes: 2692
Reputation: 1241
Yes, it's a standard practice to commit package-lock.json
.
The main reason for committing package-lock.json
is that everyone in the project is on the same package version.
Pros:
Cons:
npm install
won't make sure that everyone in the project is on the same package version. npm ci
will help with this.
Upvotes: 17
Reputation: 66730
Yes, you SHOULD:
package-lock.json
.npm ci
instead of npm install
when building your applications both on your CI and your local development machineThe npm ci
workflow requires the existence of a package-lock.json
.
A big downside of npm install
command is its unexpected behavior that it may mutate the package-lock.json
, whereas npm ci
only uses the versions specified in the lockfile and produces an error
package-lock.json
and package.json
are out of syncpackage-lock.json
is missing.Hence, running npm install
locally, esp. in larger teams with multiple developers, may lead to lots of conflicts within the package-lock.json
and developers to decide to completely delete the package-lock.json
instead.
Yet there is a strong use-case for being able to trust that the project's dependencies resolve repeatably in a reliable way across different machines.
From a package-lock.json
you get exactly that: a known-to-work state.
In the past, I had projects without package-lock.json
/ npm-shrinkwrap.json
/ yarn.lock
files whose build would fail one day because a random dependency got a breaking update.
Those issue are hard to resolve as you sometimes have to guess what the last working version was.
If you want to add a new dependency, you still run npm install {dependency}
. If you want to upgrade, use either npm update {dependency}
or npm install ${dependendency}@{version}
and commit the changed package-lock.json
.
If an upgrade fails, you can revert to the last known working package-lock.json
.
To quote npm doc:
It is highly recommended you commit the generated package lock to source control: this will allow anyone else on your team, your deployments, your CI/continuous integration, and anyone else who runs npm install in your package source to get the exact same dependency tree that you were developing on. Additionally, the diffs from these changes are human-readable and will inform you of any changes npm has made to your node_modules, so you can notice if any transitive dependencies were updated, hoisted, etc.
And in regards to the difference between npm ci
vs npm install
:
- The project must have an existing package-lock.json or npm-shrinkwrap.json.
- If dependencies in the package lock do not match those in package.json,
npm ci
will exit with an error, instead of updating the package lock.npm ci
can only install entire projects at a time: individual dependencies cannot be added with this command.- If a
node_modules
is already present, it will be automatically removed beforenpm ci
begins its install.- It will never write to
package.json
or any of the package-locks: installs are essentially frozen.
Note: I posted a similar answer here
Upvotes: 432
Reputation: 3383
To the people complaining about the noise when doing git diff:
git diff -- . ':(exclude)*package-lock.json' -- . ':(exclude)*yarn.lock'
What I did was use an alias:
alias gd="git diff --ignore-all-space --ignore-space-at-eol --ignore-space-change --ignore-blank-lines -- . ':(exclude)*package-lock.json' -- . ':(exclude)*yarn.lock'"
To ignore package-lock.json in diffs for the entire repository (everyone using it), you can add this to .gitattributes
:
package-lock.json binary
yarn.lock binary
This will result in diffs that show "Binary files a/package-lock.json and b/package-lock.json differ whenever the package lock file was changed. Additionally, some Git services (notably GitLab, but not GitHub) will also exclude these files (no more 10k lines changed!) from the diffs when viewing online when doing this.
Upvotes: 52
Reputation: 1092
My use of npm is to generate minified/uglified css/js and to generate the javascript needed in pages served by a django application. In my applications, Javascript runs on the page to create animations, some times perform ajax calls, work within a VUE framework and/or work with the css. If package-lock.json has some overriding control over what is in package.json, then it may be necessary that there is one version of this file. In my experience it either does not effect what is installed by npm install, or if it does, It has not to date adversely affected the applications I deploy to my knowledge. I don't use mongodb or other such applications that are traditionally thin client.
I remove package-lock.json from repo because npm install generates this file, and npm install is part of the deploy process on each server that runs the app. Version control of node and npm are done manually on each server, but I am careful that they are the same.
When npm install
is run on the server, it changes package-lock.json,
and if there are changes to a file that is recorded by the repo on the server, the next deploy WONT allow you to pull new changes from origin. That is
you can't deploy because the pull will overwrite the changes that have been made to package-lock.json.
You can't even overwrite a locally generated package-lock.json with what is on the repo (reset hard origin master), as npm will complain when ever you issue a command if the package-lock.json does not reflect what is in node_modules due to npm install, thus breaking the deploy. Now if this indicates that slightly different versions have been installed in node_modules, once again that has never caused me problems.
If node_modules is not on your repo (and it should not be), then package-lock.json should be ignored.
If I am missing something, please correct me in the comments, but the point that versioning is taken from this file makes no sense. The file package.json has version numbers in it, and I assume this file is the one used to build packages when npm install occurs, as when I remove it, npm install complains as follows:
jason@localhost:introcart_wagtail$ rm package.json
jason@localhost:introcart_wagtail$ npm install
npm WARN saveError ENOENT: no such file or directory, open '/home/jason/webapps/introcart_devtools/introcart_wagtail/package.json'
and the build fails, however when installing node_modules or applying npm to build js/css, no complaint is made if I remove package-lock.json
jason@localhost:introcart_wagtail$ rm package-lock.json
jason@localhost:introcart_wagtail$ npm run dev
> [email protected] dev /home/jason/webapps/introcart_devtools/introcart_wagtail
> NODE_ENV=development webpack --progress --colors --watch --mode=development
10% building 0/1 modules 1 active ...
Upvotes: 0
Reputation: 481
Yes, you can commit this file. From the npm's official docs:
package-lock.json
is automatically generated for any operations wherenpm
modifies either thenode_modules
tree, orpackage.json
. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.This file is intended to be committed into source repositories[.]
Upvotes: 25
Reputation: 670
Disable package-lock.json globally
type the following in your terminal:
npm config set package-lock false
this really work for me like magic
Upvotes: 10