npm 4 is splitting the “prepublish” script into “prepublishOnly” and “prepare”

Updated 24 Jun 2017: reflected changes in plans about npm v5..v6.

On October 20, npm is releasing v4.0.0. This release, apart from the other breaking changes, also includes one affecting a lot of packages: the prepublish npm script will be split into prepublishOnly and prepare.

📅 💥


In v1.1.71, npm made the prepublish script also execute when you run npm install without arguments. Before this, npm ran the script only before you publish a package.

The reasoning behind this isn’t clear, but as far as I’ve got it’s the following. You usually run npm install without arguments when you clone a package, go into its directory and try installing its dependencies. If you’re doing this, you’re most likely a developer, and you’re going to do something with this package; therefore it’ll be useful to prepare the package for using. Since the prepublish script often includes commands that build the package for publishing (= prepare it for using), npm decided to execute it in such case to do this job.

However, this prepublish behavior became disliked:

  • It’s weird. prepublish is pre + publish, and a lot of people didn’t assume it’s also being run when installing dependencies. I even thought it’s a bug in npm when I first discovered the way it works.

  • It creates problems. Many projects I’ve seen put building and testing commands into the prepublish script. Even npm recommends doing this. It’s convenient: it prepares the package for publishing and prevents an occasional release of broken code.
    However, if you use a CI environment like Travis or Appveyor which installs a new version of the package on each build, things become worse. Your build and test tasks get executed twice, once on npm install and once on the actual npm test. And this creates you problems such as increased build time or wrong build status.

Current behavior is disliked

What’s next#

npm 4 is splitting the prepublish script into two new: prepare and prepublishOnly.

  • prepare will have the same behavior that prepublish has now. Commands in this script will run both before publishing and on npm install.

  • prepublishOnly, as seen from its name, will run only before publishing the package.

  • Also, prepublish will receive a warning about the changes.

npm realizes that prepublishOnly is an ugly name for a script, Therefore, there’re also some other changes planned for the later releases.

  • npm 5 will un-deprecate previously deprecated prepublish, make it run only before publishing, and will deprecate prepublishOnly. In this release, prepublish will get back its expected behavior.

  • npm 6 or later will remove prepublishOnly completely. After this, two scripts will remain: prepublish which will be run only before publishing, and prepare which will be executed both on before publishing and on npm install.

Update 24 Jun 2017: the plan above was true at the moment of publishing, but seems like npm doesn’t follow it now. See a twitter thread with @maybekatz for more details.

There will be changes in npm 4…6

What to do when npm 4 is out#

Decide based on what your package needs.

  • If your package’s prepublish script contains commands that should only be run before npm publish, rename the script into prepublishOnly. Examples of such commands are npm test and eslint.
  • If your package’s prepublish script contains commands that should run both before npm publish and on npm install, rename the script to prepare. Examples of such commands are commands that build your package (e. g. webpack or babel).
  • If you don’t know, rename the script to prepublishOnly – this is the behavior most people expect. (As another option, you can leave everything as-is, but there’s no point: it will just delay the decision, but not remove it.)

P.S. If you like this, follow me on Twitter. I tweet selected articles and my own thoughts:

Author: Ivan Akulov

I’m a contracting front-end & Node.js developer. I worked with Google, EPAM, Rock Content, and others. Hire me