avatar Kisaragi Hiu

Task Runners

A task runner runs … tasks.

In the JS world, some module bundlers also act as a task runner, but it's more useful to think of the task runner as a separate thing.

Some task runners that I know of and would consider using:


Make can be seen as a task runner that happens to come with file-based dependency management.

  • Pro: Installed everywhere
  • Con: You better hope your file names never contain spaces


a-target-file: a-dependency
	echo "some shell command that runs to create a-target-file"

	touch a-dependency

	echo "this always runs"
.PHONY: a-non-file-task
# ^ this declares it to actually be a non-file task
make a-non-file-task

npm scripts

  • Pro: name tasks pre- and post- to run them before or after other tasks
  • Pro: You can run project-local tools installed with npm directly without having to specify npx
  • Con: No dependency management
  • Con: package.json has no comments.

    You can fake it by:

    But none of it beats actually having real comment syntax.


Declare your tasks in package.json:

  "scripts": {
    "dev": "python -m http.server 8080",
    "preanother": "echo 'this is special and runs before `another`'",
    "another": "npm run dev",
    "postanother": "echo 'this is special and runs after `another`'",
    "yet-another-task": "mkdir public"
npm run yet-another-task

This is also supported by Yarn (including Yarn 1):

yarn run yet-another-task

Just a bunch of scripts

A bunch of scripts will also work.

  • Pro: flexibility
  • Con: you'll most likely end up writing a bunch of boilerplate


  • ./utils/publish.sh
  • ./utils/build.sh
  • ./utils/lint.sh