How to manage npm dependencies without going crazy?

Francesca1967 IT 📗 Student 👁 74 ⚑ Report Programming

I'm working on a pretty large React project and every time I install a new package I end up with crazy version conflicts. I've tried using npm ci but it doesn't always work, especially when I'm collaborating with others. Is there a smarter way to manage this without having to start from scratch?

3 answers

★ Best answer

Never touch `package-lock.json` by hand, ever - that's the first mistake! What helped me a lot was using `npm ci` locally and especially configuring an `.npmrc` with `save-exact=true` in the project, so when you install new stuff it saves exact versions instead of `^` and `~` that cause a mess.

Then add a pre-commit hook with husky that blocks anyone trying to commit a broken `package-lock.json` - basic but it works great because the team can't accidentally mess everything up. And if you really need to add a package, always do it with `npm install --save-exact packagename` and have someone review it before you push!

When you have these conflicts, it usually happens when you install new packages with `npm install` without checking what it does to your `package-lock.json`, right?

The problem is that npm is a bit too flexible by default. First thing, make sure everyone on your team uses `npm ci` instead of `npm install` when working on an already-started project. The difference is that `npm ci` reads exactly what's in `package-lock.json` without modifying it, while `install` goes ahead and upgrades patch and minor versions whenever it feels like it. If you use `npm install` to add new stuff and then push the lock file, everyone else ends up with different versions. Also, always commit your `package-lock.json` to the repository - sounds obvious but a lot of people don't do it and then wonder why the build fails.

For new packages, use `npm install --save-exact` if you really want to freeze a specific version, or take a look at tools like `npm audit` to check if there are any known dependency conflicts. If the problem is really bad with a lot of nested dependencies, consider using `npm dedupe` every now and then to clean up your dependency tree. Actually, you could also try pnpm or yarn if you're willing to switch ecosystems - they handle dependencies in a more organized way - but if you want to stick with npm, following the `ci` + `package-lock.json` in git workflow should solve most of the mess.

Francesca1967 asker Yes, we always commit the lock file. The problem is that some colleagues still use `npm install` to add new packages. I'll try to standardize on `npm ci` and `--save-exact` for new packages.

The thing that really saved me is always using `npm ci`, but most importantly making sure the whole team does it - not `npm install`. The moment someone does a standard `install` to add a package, the `package-lock.json` gets modified in weird ways and then everyone else ends up with absurd merge conflicts.

What I do is use `npm install <package> --save` only when I need to add new stuff, and let the lock file update, then commit everything together.

But the real trick is configuring versions in `package.json` with more conservative ranges - like `^16.0.0` instead of `*` - so React doesn't update itself to a minor version that breaks everything. I've seen big projects where they simply put a common `.npmrc` file in the repo with `save-exact=true`, so every new package gets pinned to an exact version. It's more rigid, but at least you don't go crazy when you're collaborating.

Your answer

Log into answer.