How to organise NPM scripts in package.json?

ycmjason profile image Jason Yu ・2 min read

I love using npm script as my build tool. By doing so, we could make sure the scripts are not sooooo complicated and easy to read (comparing to gulp/grunt in my opinion).

But as the project grows larger, there are more and more scripts that are added to package.json and things become less and less maintainable.

You probably tried adding empty lines in between scripts, but figure npm install will just remove your empty lines and leave you with only disappointment.

Here is a little trick which allow us to, kind of, group our scripts into categories.

  "scripts": {
    "test": "nyc mocha --recursive",
    "preversion": "git checkout master && git merge --squash dev && npm test",
    "version": "git add -A",
    "postversion": "git push && git push --tags && git checkout -",
    "\n# TESTING SCRIPTS:": "",
    "createTestPages": "node ./scripts/createTestPages.js",
    "test:watch": "mocha --recursive --watch",
    "coverage": "nyc report --reporter=lcov > coverage.lcov && codecov",
    "lint:js": "eslint .",
    "\n# HUSKY GIT HOOKS:": "",
    "precommit": "lint-staged"

The trick here is to define some category keys. By adding \n to the front of the key, we would get a pretty darn neat npm run result.

> npm run
Lifecycle scripts included in grab-lyrics:
    nyc mocha --recursive
    git checkout master && git merge --squash dev && npm test
    git add -A
    git push && git push --tags && git checkout -

available via `npm run-script`:


    node ./scripts/createTestPages.js
    mocha --recursive --watch
    nyc report --reporter=lcov > coverage.lcov && codecov
    eslint .



One thing to keep in mind is to always put NPM lifecycle hooks at the top of the script because NPM will just grab them and put them at the top.

What do you think about this trick?


Editor guide
rafegoldberg profile image
Rafe Goldberg

I see the reasoning behind your approach, but – at least for a production-ready project – it feels a bit hack-y to me!

An alternative organizational method might be to move your NPM script definitions in to their own dedicated shell files within a build/ directory. This way, you can organize your script files without having to pepper your package.json with unnecessary entries. Though it won't give you the pretty npm run section headers you demonstrated (obviously), the directory structure gives you a similar kind of at-a-glance legibility. And using dedicate shell scripts will definitely simplify long-term package maintenance...

Anyway, just my two-cents; thanks for thinking!

ycmjason profile image
Jason Yu Author

I definitely agree with you. A build/ directory is definitely better for production projects.

But, I think this is a hack that wouldn't really hurt to add. It is not at all contradictory to having build/. And the good thing about it is the pretty npm run that will give a nicer guidelines to, maybe new developers who wants to find out the building instructions available.

rafegoldberg profile image
Rafe Goldberg

[these two approaches are] not at all contradictory... and the good thing about it is the pretty npm run

true enough. especially re: those “new developers who want to find... instructions”, a file system abstraction is probably suboptimal!

17cupsofcoffee profile image
Joe Clay

This is a cool trick :)

Makes me wish Node/NPM had used a file format that supports comments, though - Rust uses TOML, and it's hard to go back to JSON for config files after using that :(

ycmjason profile image
Jason Yu Author

Yes! Although it isn't really a solution, it does the trick if we want a neater npm run output.

I am happy you find this trick useful.