Hello 👋

I'm Alejandro

A Web Engineer from Málaga, Spain based in London, UK

Understanding NPM Scripts

Have you ever thought about creating your own command line tool? Well, here is your chance to create one for your project.

What are NPM Scripts?

NPM scripts is a simple solution to automate any repetitive tasks. For example, building your project, starting a server, minifying your assets...etc.

I'm not sure if you remember the time when we had only tools like grunt or gulp in which we had a huge configuration file to automate tasks, but those were pretty horrific.

With NPM scripts life is much simpler.

Now that you know what they are, we should write an example:

Let's say we wanted to start a node server from our application. What you would normally do from the command line, will look something like this:

node index.js --port 8080

If we wanted to automate this with NPM Scripts, all we needed to do is:

  1. Create a "scripts" property on our package.json file (this being an object).
  2. Inside "scripts" create a property, let's call it "start" and give it the value of your command.

Simple right? At the end you will have something like this:

  "scripts": {
    "start": "node index.js --port 8080"

and you can just run

npm start

from your command line, and the respective command will be runned for you.

Why NPM Scripts?

Why should I be using NPM Script instead of writing my command directly on the terminal? Well, there are various reasons why, with the first being... Will you always remember this command and the way you should start your project? Even if you come back in 3 months time?

NPM Scripts is not only a command tool, but the entry point of your project. The place where you should always go when starting to view a javascript/npm related project from.

Also, imagine your project becomes more complex, and you no longer have one command, but 10 instead. One to run your unit tests, another to build assets, another to optimise svg icons, another to run your end-2-end tests...etc. Your memory will no longer keep track of those and you will need to go back to documentation of every single tool you use and refresh your mind.

If you think your project cannot become complex, have a look at next.js's scripts section on their package.json file.

"scripts": {
  "lerna": "lerna",
  "dev": "lerna run build --stream --parallel",
  "dev2": "while true; do yarn --check-files && yarn dev; done",
  "testonly": "jest --runInBand",
  "testheadless": "cross-env HEADLESS=true yarn testonly",
  "testsafari": "cross-env BROWSER_NAME=safari yarn testonly",
  "testfirefox": "cross-env BROWSER_NAME=firefox yarn testonly",
  "testie": "cross-env BROWSER_NAME=\"internet explorer\" yarn testonly",
  "testall": "yarn run testonly -- --ci --forceExit",
  "pretest": "yarn run lint",
  "git-reset": "git reset --hard HEAD",
  "git-clean": "git clean -d -x -e node_modules -e packages -f",
  "test-take2": "yarn git-reset && yarn git-clean && yarn testall",
  "test": "yarn run testall || yarn run test-take2",
  "lint-typescript": "lerna run typescript",
  "lint-eslint": "eslint . --ext js,jsx,ts,tsx --max-warnings=0",
  "lint": "run-p lint-typescript prettier-check lint-eslint",
  "lint-fix": "yarn prettier-fix && eslint . --ext js,jsx,ts,tsx --fix --max-warnings=0",
  "prettier-check": "prettier --check \"**/*.{js,jsx,json,ts,tsx,md,mdx,css,html,yml,yaml,scss,sass}\"",
  "prettier-fix": "prettier --write \"**/*.{js,jsx,json,ts,tsx,md,mdx,css,html,yml,yaml,scss,sass}\"",
  "types": "lerna run types --stream",
  "typescript": "lerna run typescript",
  "prepublish": "lerna run prepublish",
  "publish-canary": "lerna version prerelease --preid canary --force-publish && release --pre",
  "publish-stable": "lerna version --force-publish",
  "lint-staged": "lint-staged",
  "next": "node packages/next/dist/bin/next"

Secrets of NPM Scripts

Script names

NPM has some special names for common commands, but you can always create custom ones (more on that later).

I will focus on two to make your reading simple, but you can go here to read about more.

  • start is commonly used to start your application, normally to run a server.
  • test is commonly used to run your test.

Those are some of the names NPM have chosen as common tasks every project should have. And because of that, there are special ways to run those:

You could also run npm start with

npm s

and you could also run npm test with

npm t

Even simpler right?

Pre and Post hooks

What if I tell you there is a built-in way to run something before and after running your command.

For example, if you wanted to run eslint before running your tests, all you have to do is create a "pretest" script on your package.json file.

  "scripts": {
    "test": "jest",
    "pretest": "eslint . --ext js,jsx,ts,tsx --max-warnings=0"

Same story with post, but in this case it will run after the test command.

Having pretest, test and posttest, all you need to do now, is run:

npm t

and the three will run in order, first pretest, then test and then posttest.

Isn't that super flexible? Well, wait for more!

Custom scripts

You can run a script however you want. But notice, because npm will not recognise those as common/predefined script, there is another way to execute them.

If we wanted to create a bundle-assets script that will run webpack to bundle and minify our assets, we will do that this way:

  "scripts": {
    "bundle-assets": "webpack"

But now, you will need to execute it this way:

npm run bundle-assets

Just adding the word run in the middle, NPM will let you execute your custom named command.

NOTE: You can continue using pre/post hooks with custom commands. (eg. prebundle-assets and postbundle-assets)

In review

Automating tasks is easier with NPM Scripts. They provide a flexible and customizable API.

NPM Scripts is the command line tool of yuor project.

All you need is:

  1. A package.json file.
  2. A "scripts" section.
  3. Some custom scripts to enhance your project.

And remember:

  1. You can use the name you want.
  2. You can use pre/post hooks.
Share this post

Read more about