I contrast this with node/npm where my projects seem to behave identically across deployments (and in some cases, when in a bind, I've even been able to simply tar & scp the project src and have it run without further effort beyond installing node, something I've never been able to do with ruby).
That's where semantic versioning comes in. Most libraries follow it - if the major version number changes, it's a breaking change. If it doesn't, you're safe to upgrade.
There are some major libraries that are on version 15 or greater... there's nothing good from a user's perspective about having a library they use do a major breaking release every other month.
What's worse is many libraries take advantage of "it's the wild west until 1.0" rule in semver and simple never release a 1.0.
It's not just Node itself to blame. There seems to be a culture of breaking things in the Node.js ecosystem. Breaking changes in third-party libraries are common. I have to specify exact dependency versions in my package.json, and almost every time I update one of them, something goes wrong.