What is a CLI?
To start with some definition, CLI stands for command-line interface.
If you are not too familiar with "building CLI" or even the terminal, it might look like a black box for you. You might even think: "No way I'm going to learn bash, or whatever it is called, to build these tools".
The good news is: you do not need
bash to build a CLI tool! Even though I like bash.
You can build CLI tools with a lot of different languages, like:
C++ and even...
All the following commands will be executed in a Unix Shell (bash).
Here is my favourite NodeJS CLI, type the following in your terminal:
npm install -g cowsay
cowsay "I'm running in NodeJS"
Which will output:
< I'm running in NodeJS >
A little trick, you can also run it without installing it, using npx:
npx cowsay "I'm running in NodeJS"
Get started building a CLI
To create a CLI with NodeJS, there are a few pieces to put together.
Execute a node script
The first part is the be able to execute a node script.
A common way
- Create a file
- Write some content
- Execute it with NodeJS
echo 'console.log("Hello");' > my-script.js
A more elegant way
- create a file
- Tell the shell in which environment it should run the script (shebang)
- Make the file executable with chmod
- Execute the file without specifying NodeJS
echo '#!/usr/bin/env node' > my-script.js
echo 'console.log("Hello");' >> my-script.js
chmod +x my-script.js
You can see the same type of file in the
cowsay repo: cli.js.
Execute the script as a binary
The second part is to transform this script into a command line.
There is an easy way to do that by adding the script to a
bin property of a
There is a little bit of magic around this: when this package gets installed,
npm will create symlinks for the scripts in a
bin folder so that your shell can find the "binaries".
For example, when you install
cowsay, the terminal outputs:
/usr/local/bin/cowthink -> /usr/local/lib/node_modules/cowsay/cli.js
/usr/local/bin/cowsay -> /usr/local/lib/node_modules/cowsay/cli.js
added 41 packages from 10 contributors in 3.028s
These are the symlinks created and they are now ready to use in your terminal.
A little trick for local development, in the folder where the
package.json is located, you can simply run:
This command will also create the symlinks needed. They can be removed with:
Create a compliant CLI
Now you can execute a CLI you made yourself, you can simply write some NodeJS code. You create and modify some files, parse some JSON files, make some asynchronous requests to an API like Github, upload some files to an AWS S3, and so on.
You can now build your own tools, make them do what you need, and execute them easily.
What might seem less easy to do, is to write a proper Unix CLI like others would expect, like:
my-cli do-something --some-option
You need to think about writing help output, version output, subcommands, options that can be chained, with short name options, and so on. And of course in a format that would make all your heavy Unix CLI users happy.
Here is a guideline: clig.dev.
Fortunately, some packages provide really good boilerplates for your CLI tools, for example, commander.
Distribution and usage
To distribute your CLI, you can simply publish your package to the
npm registry. This is will make it available to everyone, don't forget to write some tests and some thorough documentation!
In terms of usage, you can simply install it:
npm install -g my-cli
Another scenario is if you do not want to publish the
npm package because you want to keep the CLI in a private repo, you can simply clone your repo and execute the following:
It is also possible to execute the command without installing it before, for example on a CI, by using
npx and targeting the package:
npx -p my-npm-package my-cli --help