JOSHUA HOLBROOK github : twitter

Node.JS's `engines` Field Is Broken (posted 05 Nov 2011)


I’ve noticed something interesting during the v0.6.0 release of Node.JS:

Basically, people trying to use v0.6.0 are fucked right now because the current behavior and use of the engines field is broken.

(I always kinda wanted to make some kind of rash accusation like this. I feel like a real blogger now!)

Here’s an example as to why the engines field is bad: The other day, I got a pull request for one of my modules, sendgrid-web:

Update package.json

Had to make a couple changes to make this installable on node v0.4.12 and npm 1.0.9-1

@@ -2,7 +2,7 @@
   "author": "Joshua Holbrook <josh.holbrook@gmail.com> (http://jesusabdullah.github.com)",
   "name": "sendgrid-web",
   "description": "Easily send emails with sendgrid and node.js",
-  "version": "0.0.0",
+  "version": "0.0.1",
   "homepage": "https://github.com/jesusabdullah/node-sendgrid-web",
   "repository": {
     "type": "git",
...	 ...	
@@ -13,7 +13,7 @@
     "test": "nodeunit test/*.js"
   },
   "engines": {
-    "node": "~v0.4.9"
+    "node": "0.4.X"
   },
   "dependencies": {
     "request": "2.1.x"

You can see the original pull request here.

In order to make this module work in node v0.4.12, someone had to change the engines field to allow it, even though the module otherwise runs in node v0.4.12 without modification. This problem probably shouldn’t have happened in this case (isn’t ~v0.4.9 equivalent to 0.4.x with x >= 9?), but in the case of 0.5.x and 0.6.x node installs, it’s a real issue for libraries everywhere.

For dependencies, managing versions tightly is a good idea, especially with npm’s behavior. As it stands, npm downloads the latest version that meets your semver criteria and just runs it. npm even handles mismatched versions admirably, by allowing libraries to require separate versions of each library. Because of this behavior, using tight semvers on your dependencies makes sure that your library will continue to work.

On the other hand, you can’t just install node itself as a dependency, so all npm can do is not let you try running the software, even if it will work without modifications.

So, like I said, people trying to use v0.6.0 are hosed right now.

On the other hand, people still specify tight versions for engines.node . I think that it seems like the right thing to do, because we do this for libraries and because in libraries it’s considered bad impolite to hand somebody a module that breaks. That seems admirable.

On the other hand, though, this causes modules to actually break more often, because it stops them from running regardless of whether it would actually Just Work or not.

I’m not really sure what to do about it, though. Here are some ideas:

  • Encode engines.node as “*”, or ditch the engines field completely
  • Add a way to explicitly override engines checking, such as an “ARE YOU SURE?” prompt
  • Write a system that will run modules using their specified node version by managing multiple versions of node in the background (which, as SubStizzy would prefer, could use the “dependencies” field to encode this information instead, allowing us to still encode engines.node as “*” or ditch it completely.)

I’m fairly well convinced that the idea of engines is a reasonable one. I don’t, however, think we’re using it as well as we could be.