[BUG] npm install does not include pre-release when determining version to install
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 installing via npm install our-library@">4.2.0-beta", npm does not find any version to install. It ignores any pre-release version unless you specify the exact pre-release version. Same with npm outdated, it does show that there is a new pre-release version available in the Latest column, but Wanted column is always current installed pre-release version. I have tried using >4.2.0-beta, ^4.2.0-beta, and ~4.2.0-beta. None will cause the outdated to show the new pre-release as wanted.
Expected Behavior
With the use of >4.2.0-beta, outdated and install should consider pre-release versions. Or add a command line switch to enable looking for pre-release versions.
Steps To Reproduce
Installing
- Build library that has pre-release version
1.0.1-beta-123and publish it to npm repo. - Try to install using
>1.0.0-beta
Updating
- Build library that has pre-release version
1.0.1-beta-123and publish it to npm repo. - Install using
@^1.0.1-beta-123 - Build new pre-release version
1.0.2-beta-456and publish it to npm repo. - Run
npm outdated. Wanted shows1.0.1-beta-123, Latest shows1.0.2-beta-456
Environment
- npm: 10.9.0
- Node.js: v21.7.3
- OS Name: Windows 11
- npm config:
This is by design, in all versions of npm. If you want prereleases included, the range has to explicitly include them, at each level.
@ljharb this bug report is pointing out that the range does not work at all for pre-release.
beta-123 and beta-456 are incompatible prerelease categories. Perhaps you want beta.123 and beta.456?
I have tried all different types of formats. I just changed it to using a dash instead of period to test if it would work. And why are stating it is incompatible, it adheres to semver formatting.
Also this, doesn't seem to accept the range.
> npm install our-library@">4.2.32-beta.ge8343d1e"
npm error code ETARGET
npm error notarget No matching version found for our-library@>4.2.32-beta.ge8343d1e.
npm error notarget In most cases you or one of your dependencies are requesting
npm error notarget a package version that doesn't exist.
It's certainly valid - i just meant that they're two completely different buckets. In that latter example, use ^ instead of >, and i'd expect it to work.
It installs with ^ but it does not find any later pre-releases upon running the outdated command. The pre-release is stuck as Wanted, and the newer pre-release is in Latest. There is no way to update your pre-release installed version using npm update. You have to manually run install again with the new pre-release version.
hm, i wonder if that's because the part after the dot isn't numeric?
Should the value after the dot even come into play yet, as the patch number is already higher in the newer pre-release
Example
>npm install our-library@^4.2.29-beta.g8c00b605
npm warn deprecated @npmcli/[email protected]: This functionality has been moved to @npmcli/fs
npm warn deprecated @npmcli/[email protected]: This functionality has been moved to @npmcli/fs
added 5 packages, and audited 1427 packages in 9s
162 packages are looking for funding
run `npm fund` for details
25 vulnerabilities (2 low, 8 moderate, 11 high, 4 critical)
To address all issues, run:
npm audit fix
Run `npm audit` for details.
>npm outdated our-library
Package Current Wanted Latest Location Depended by
our-library 4.2.29-beta.g8c00b605 4.2.29-beta.g8c00b605 4.2.37-beta-439e0756 node_modules/our-library project
>npm update our-library
npm warn deprecated @npmcli/[email protected]: This functionality has been moved to @npmcli/fs
npm warn deprecated @npmcli/[email protected]: This functionality has been moved to @npmcli/fs
up to date, audited 1427 packages in 6s
162 packages are looking for funding
run `npm fund` for details
27 vulnerabilities (2 low, 9 moderate, 12 high, 4 critical)
To address all issues, run:
npm audit fix
Run `npm audit` for details.
oh! i missed that. prereleases are for a specific version triple. your range there can only ever match prereleases for v4.2.32. Prereleases for a higher version need their own explicit range.
In other words, typically people only make prereleases for a new major version, because that way ^X.0.0-0 can cover all of them for a given X.
That may be true and valid for public pre-releases, but for internal teams working off of shared libraries in repos, our patch versions increase with each build. The part after the period is just the commit hash of git.
How can we get a feature added then to have a command line switch or a setting in packages.json to allow upgrading pre-releases like normal releases?
The commit hash seems like something that would go in the build signifier (+), which npm doesn't support and actively strips.
Is there a reason you can't just use normal patch versions?
We are using patch version, as you can see that the patch version increments on each build 4.2.29-beta -> 4.2.37-beta
Sorry, i meant, non-prerelease patch versions. Like, just 4.2.29 and 4.2.37. Then you'd get all the semver ranges you want.
Prereleases are meant for one-off testing, not for parallel release lines.
That is a difference of opinion. Pre-release build is just that, a release that is not stable, not one-off tests. They are versions of the code that can be used while development is going on. Especially for large projects that have different libraries.
I mean, given the way npm has implemented semver and ranges forever, it's a bit more concrete than opinion. It's not going to work for what you want, unfortunately.
Ok, it is a npm opinion, but that should not force it upon everyone. npm is merely a package manager, it should not dictate a team's way of versioning when the team is perfectly aligned with the versioning scheme the package manager is supposed to conform to. Plus, if you go to npm documentation, they literally point you to an example search interface that explains how to select based on pre-release ranges... Why would it not work the way most folks would expect it to work, and most all other package managers work? Not asking to rewrite it, I am asking for an opt-in way of enabling it to work.
Also, just because something is always done a certain way doesn't mean change can't be made for improvement. Otherwise, we would still be writing in assembly...
The special prerelease behaviour is surprising the first time you hit it when expecting a different behaviour.
There is extensive coverage in the semver README which explains the behaviour and the rationale: https://github.com/npm/node-semver#prerelease-tags
(@ljharb touched on the key issues above, but the README lays it out nicely.)
You might get most of what you want by not updating the patch version with every build? Conventionally 4.2.32-beta.ge8343d1e is a pre-release build of 4.2.32. What "release" are you heading towards? You can include a build number in the prerelease information like: 4.2.32-beta.1.ge8343d1e, or treating the hash as meta information: 4.2.32-beta.1+ge8343d1e
The underlying semver package supports a includePrerelease flag which is what you asked for, but as far as I can see that is not exposed by the npm CLI configuration.