Package.json: Caret vs. pinned versions?

What is the current opinion on using caret versions (like "ionic-angular": "^3.8.0",) vs. pinned versions ("ionic-angular": "3.8.0",) in package.json? Which one makes more sense and why?

It depends on the package, and where you are at in your dev cycle. If you are about to publish, maybe you want to freeze all updates, so no breaking change gets introduced accidentally. If you are earlier in dev, you probably want to update aggressively, so you have the most curent software when you decide to freeze updates.

Now to packages. Use ^ with all ionic things, like ionic-angular, native, app-scripts. You want to stay as current as possible. But with Angular and Typescript, DO NOT use the caret, because the newest versions of Angular and Typescript sometimes break Ionic. (As I write this, I think newest Angular is ok, but newest Typescript is definitely not ok.)

For other libraries, it depends on the situation. Use the caret if you want to update. Don’t if you want to freeze updates. Decide which is better based on the criteria above.

2 Likes

So in general the “end goal” should be to have pinned versions to make the build as reproducible as possible, right?

What about lock files that newer versions of NPM introduced? Can these replace the pinning?

That’s a bit of a separate issue. There are two sections in package.json where you can specify dependencies – libraries your app needs in order to run correctly. In general you DO want to use the caret there, because libraries agree to follow semver rules in order to be in the npm registry, and npm knows the difference between updating a better edition of version 1, and updating from version 1 to breaking changes in version 2.

BTW: package.json can be seen as the versioning rules, while package.lock.json is a record of exactly which versions were used for the most recent compilation.

Isn’t it highly relevant which software actually gets built by the devDependencies? That’s what I meant with that comment as this depends on which versions are installed in node_modules per the package.json.

That’s true, if package-lock.json is used when downloading and installing packages it doesn’t really matter if the versions are pinned or with carets or other “qualifiers”, right?

If you’re sharing with another dev on your team, yes. If you’re publishing to npm, no. To a consumer of your library, the devDependencies are not relevant.

What sections are you talking about here then? Not dependencies and devDependencies?

Yes, those two. They’re separated for a reason. devDependencies are intended to be useful during development.
Edit: link: https://docs.npmjs.com/getting-started/using-a-package.json#specifying-dependencies