cli
cli copied to clipboard
[FEATURE] npm ci --global is not supported
Is there an existing issue for this?
- [X] I have searched the existing issues
This issue exists in the latest npm version
- [X] I am using the latest npm
Current Behavior
When trying npm ci --global the following is returned: npm ERR! npm ci does not work for global packages.
Expected Behavior
I'm trying to migrate a command line tool from Yarn. Currently I would run
yarn install ./my-cli-tool-written-in-nodejs --global --frozen-lockfile
...and this command installs my package globally while strictly adhering to the contents of my lock file. Seemingly equivalent to --frozen-lockfile is npm ci but this command does not appear to support this behavior.
In #5698 this topic was left unresolved and closed, yet the problem persists. Thats for considering.
Steps To Reproduce
npm ci $package --global
Environment
- npm 10.2.4
- node v21.6.1
- macOS 14.2.1
npm ci requires a package.json, which doesn't exist for globally installed packages.
Also, npm install and npm ci are mutually exclusive, you use one or the other.
npm cirequires a package.json
Per the docs here: https://docs.npmjs.com/cli/v10/commands/npm-ci
This command is similar to npm install, except it's meant to be used in automated environments such as test platforms, continuous integration, and deployment -- or any situation where you want to make sure you're doing a clean install of your dependencies.
This is exactly what I want to use npm ci for
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.
Makes sense; my project has both a package.json and package-lock.json to inform the global installation of my CLI tool. Notably Yarn does the right thing here; it globally installs my package using yarn.lock — it's not clear why npm ci cannot do this. Instead the behavior forces us to accept that npm install may rewrite my package-lock.json during continuous integration of my globally installed CLI tool. This isn't really acceptable.
Also thanks for pointing out the mistake in my sample; the command I want to run is npm ci not npm ci install
Best practice is to not install anything globally, especially in a CI environment. Instead, you install it locally and invoke it with npx.
The entire purpose of npm ci is to delete and reinstall local node_modules. It's just conceptually nonsense to use it with -g.
@ljharb are you a maintainer of npm or npm ci?
@klebba nope! but that doesn't make any of my statements less true.
I see. Well, you know, that's just like uh, your opinion, man.
As long as npm install --global is a supported feature it is rather bizarre to randomly admonish issue reporters about "best practices" and "nonsense" use cases.
npm install -g is supported. npm ci -g is not, by design, since its inception.
Teaching best practices is a gift - it's trying to help you.
npm ci installs a package as a dependency of the global namespace. It is fundamentally different than installing the dependencies for a package. There is no global package.json, so there is no ci that could be done at that level.
For cli tools in which you wan to dictate exactly what is installed when your package is installed (which npm itself does) you want to bundle your dependencies. Please note that yarn et al don't support that. You may also be thinking of a shrinkwrap which does what you are describing.
Thanks for your reply. Yarn does support what I want; I already use it like this:
yarn install ./my-cli-tool-written-in-nodejs --global --frozen-lockfile
According to npm ci docs the command should satisfy the use case:
This command is similar to npm install, except it's meant to be used in automated environments such as test platforms, continuous integration, and deployment --
or any situation where you want to make sure you're doing a clean install of your dependencies.
The project must have an existing package-lock.json or npm-shrinkwrap.json.
Yes
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.
Yes
npm ci can only install entire projects at a time: individual dependencies cannot be added with this command.
Yes
If a node_modules is already present, it will be automatically removed before npm ci begins its install.
Yes
It will never write to package.json or any of the package-locks: installs are essentially frozen.
Yes
Thanks for pointing out npm shrinkwrap — this does seem like what I need. In fact now it's not clear to me why I would use npm ci instead of npm install if I want to adhere to lockfile contents. I guess something about whether or not the lockfile is publishable?
I could update this ticket or open another with adjusted suggestions:
- Update the
npm cicommand docs to indicate thatnpm ciis not/will never be able to install packages globally, instead refer users to adoptnpm shrinkwrapand usenpm installto accomplish this task. - Consider addressing / reconciling these two confusing statements:
use
npm ciwhen you need to strictly adhere to the contents of your lockfile defined inpackage-lock.jsonORnpm-shrinkwrap.jsonfor a local install
use
npm installwhen you need to strictly adhere to the contents of your lockfile defined ONLY innpm-shrinkwrap.jsonfor a global install
As I write this I also wonder: why can't I use npm install to strictly adhere to my package-lock.json (e.g. frozen install)?