Differences between standard npm install and workspace npm install regarding package-lock.json

I’m trying to figure out how package-lock.json files are handled differently between npm workspaces and standard npm commands.

I have a project setup like this:

./project-root/
./project-root/package.json
./project-root/app/
./project-root/app/package.json
./project-root/api/
./project-root/api/package.json

When I run npm install from the main ./project-root/ directory, it creates a ./project-root/package-lock.json file at the root level without generating any lock files for the submodules.

Using npm --workspace=app install seems to show no changes compared to the previous command.

However, when I run npm --prefix=app install, this command does create a separate ./project-root/app/package-lock.json file.

To further investigate, I switched to the api directory with cd api and executed npm install, but this does not create a ./api/package-lock.json file either.

This inconsistency is causing problems in my CI setup. If I update dependencies and mistakenly run npm install from an individual module, my build fails because the CI is expecting npm ci to find synchronized package.json and package-lock.json files in the same directory.

Can anyone shed light on why these different npm commands behave in such a contradictory manner? I’m currently using Node 22.5.1 with NPM 10.8.2.

totally get where ur coming from! npm workspaces can get really weird with those lock files. yeah, --prefix is def the way to go for separate lock files. just make sure ur CI is set up to expect what it needs, or it can get messy! good luck!

This is actually how npm workspaces are supposed to work. When you run npm install from the root, npm treats everything as one big dependency tree and creates a single lock file at the top. That’s how it keeps dependencies consistent across all your workspaces. Using --prefix=app is different - it completely ignores the workspace setup and treats that app folder like it’s its own separate project. That’s why you get a lock file there. When you cd into the api folder and run npm install, npm sees you’re in a workspace and just uses the root lock file instead of making a new one. For your CI, pick one approach and stick with it. Either use workspaces everywhere or treat each package separately. If you need separate lock files for deployment, you can use --prefix commands throughout, but you’ll lose all the workspace dependency management benefits.

You’re encountering the behavior of npm’s workspace resolution. When npm detects a workspace configuration in your root package.json, it centralizes the management of dependencies, resulting in a single lock file at the root level. Therefore, executing npm install within a workspace subdirectory like your api folder does not create local lock files; it relies on the root-level management instead.

On the other hand, using the --prefix flag circumvents the workspace detection and treats the specified directory as a separate npm project, hence generating individual lock files.

For your CI pipeline, consider using npm ci --workspaces from the project root to maintain the single lock file strategy while correctly installing all workspace dependencies. However, if you require distinct control over individual packages, you may need to abandon workspaces altogether and manage each as a standalone project with separate lock files.