Task runners like Gulp or Grunt have been go to choice for the front end projects for last few years. Gulp being the latest between the two, and being the popular choice for last couple of years, one might wonder what’s wrong with it.

But as your project gets large, your tasks runners get bloated as well, and sooner you will run into various issues.

Issues with Gulp and Grunt

Task runners like Gulp and Grunt have few common problems.

  • Requires plugins for different tasks
  • Too much or lack of documentation
  • Difficult to debug

Requires plugins for different tasks

With Gulp and Grunt, tasks are run using plugins. Managing plugins becomes a nightmare when they are outdated. Some plugins may have bugs and you will have to wait for the plugin author to fix them before using it.

When using NPM though, you are using the tools directly.

Too much or lack of Documentation

Plugins mean extra documentation. If you are using a plugin to use a tool, you would have to use both documentation for both the plugin and the tool.

Usually the documentation for the tools are comprehensive than the plugins.

Difficult to Debug

Debugging in Gulp or Grunt can be a frustrating task as you are working with an extra level of abstraction.

The cause for a bug could be one of the many from the below:

  • Broken plugin
  • Broken tool
  • Bad configuration
  • Incompatible version

If you were using NPM instead, you completely eliminate the first issue on the list.

NPM Scripts

In the core of NPM, it has a the npm run-script command, or the shorter version npm run. This will access the script property in the package.json. It will pass a property inside the scripts object as its first parameter and execute the property’s value as command in the operating system’s default shell.

  "name": "project-name",
  "devDependencies": {
    "jshint": "latest",
    "mocha": "latest"
  "scripts": {
    "lint": "jshint test/*.js",
    "test": "mocha test/"

The shell environment sets your node_modules/.bin folder added to the PATH so that the binaries installed can be run directly. This means you don’t have to rely on installing runnables globally.

Running npm run should give you the available options to run.

npm run


available via `npm run-script`:
jshint **/*.js

You also can retrieve extra metadata about your current environment by adding env as a property to the scripts.

"scripts": {
    "env": "env"


NPM provides few very useful shortcuts for us.

  • npm start – runs the project on the given port for development
  • npm stop – stops a running project in development
  • npm test – standard interface within NPM for test.

These are shortcuts for the command npm run.

Pre and Post Hooks

NPM gives you a set of pre and post task in the means of pre- and post- hooks.

For example for npm test which is the shortcut for npm run test, has pre and post scripts in `npm run pretest and npm run posttest`.

Exit Code Sensitivity

Pre and post scripts will stop immediately if the exit code is non-zero.

NPM runs pre and post hooks for few internal commands:

  • install
  • uninstall
  • publish
  • update

Let’s look at an example.

  "name": "npm-scripts",
  "version": "1.0.0",
  "description": "NPM as a build tool demo",
  "main": "index.js",
  "scripts": {
    "env": "env",
    "lint": "jshint **/*.js",
    "test": "mocha test",
    "build": "babel src -d lib",
    "prepublish": "",
    "prebuild": "npm run lint",
    "pretest": ""
  "keywords": [
  "author": "Sean Amarasinghe",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.0.0",
    "jshint": "^2.9.2",
    "mocha": "^2.5.3"


Hopefully yhis article would motivate you to select NPM as the build tool for your next project. Or replace exisiting Gulp or Grunt tasks with NPM.