How to Build a Command Line (CLI) Tool in NodeJS

Learn how to build a command-line app in NodeJS.

Since the advent of Nodejs, command-line tools have been built using the JavaScript programming language, the most popular and widely used language in the world. There are many popular CLI tools built using JS:

These are popular CLI tools we have in npmjs.org. NPM is the world most popular Node package manager. You reading this, you must have worked with Nodejs, and there is no way you haven’t used the popular npm command with its helluva pile of sub-commands:

publish

init

cache clean

etc

Tip: Share utility and UI components

Use Bit to easily publish, install and update small individual modules across different JavaScript projects. Don’t install entire libraries and don’t copy-paste code, when you can build faster with small reusable modules. Take a look.

Bit: Easily reuse and sync small modules and utils across JS projects

Short intro

You see, Nodejs made us be able to write command-line tools in our fav language: JS. Without Nodejs, we will just write a cmd0line in C/C++ and compile to executable. We know the popular commands we use in cmd/bash:

ls

touch

mkdir

cd

etc

These are executable files(.exe, .app, in Linux systems there is no file extension) in our system path, written in C/C++ and compiled to executable format. If we run the ls command to list files and folders in our current directory:

$ ls 'autorun.inf/' 'System Information/'

The ls file is forked and run, the results it returns is displayed on the cmd/bash/sh.

we can create our our program and run it in cmd-line:

// hello.cpp

#include <iostream>; int main() {

cout >> "Hello world";

return 0;

}

On compilation, we will have the executable file hello.exe . On execution in he cmd-line, it will display "Hello world" in the cmd:

$ hello

Hello world

You see, this is a CLI tool written in C/C++ but with Nodejs we can write the same in JavaScript, can you imagine that? A language we knew from the beginning of our programming journey that it was a browser-based language, can now be used to create CLI utilities that can be done in C/C++.

So, in this post, we will see how to write a CLI tool in JS.

Project Setup

First, you need to download the Nodejs program and install it. Open your browser and navigate to https://nodejs.org and there on the main page you can download the version of Node.js that corresponds to your platform.

Next, we have to initialize a Node project:

mkdir node-cli

cd node-cli

npm init -y

This app will mimic our hello.cpp program it will just output "Hello world" in the terminal.

We create an index.js file

touch index.js

Open it and pour in the below contents:

// index.js

console.log("Hello world");

If we run node . in our terminal, we will see the contents display:

$ node .

Hello world

We added . to the node command because the entry point is the index.js so Node will know to run the index.js file which is the default file for any Node project. If we create a file like hello.js , to run it we must specify its name in the node command: node hello or node hello.js .

I know, a Hello world program isn't ideal to demonstrate a concept but this isn't about the example it is about how to make a shell-command line program in Nodejs.

Making our project a Shell-Cmd

Our program is called with the node command, we want it to be called like a regular shell command like how the Angular CLI is called: ng .

It is very easy to achieve. First we add #!/usr/bin/env node to the index.js file:

// index.js

#!/usr/bin/env node console.log("Hello world");

This makes it possible to execute this project without the node command. See it has already been added in the command #!/usr/bin/env node .

Next, we need to update our package.json file:

// package.json

{

name: "node-cli",

// ...

bin: "./index.js"

// ...

}

See we added a bin property with the value pointed to the index.js file. The bin prop specifies command names for a node project, but as we have a single file the name property will be used as the shell command name.

Now our app is not globally available like we cannot run node-cli in our shell to run the project. But we don’t want the CLI name to be node-cli, we want it to be hello, so we can run it like this: hello . To do that we will change the name property in the package.json to hello .

// package.json

{

name: "hello",

// ...

bin: "./index.js"

// ...

}

Making our project globally available

To make our project available globally we would create a symlink using the npm link command.

We run:

npm link

yarn link

in our project. This command creates a symbolic link between the project directory and executable command.

In Windows, you will see hello.cmd created in ~/Admin/AppData/LocalRoaming/npm , the hello.cmd is the file that will be run when we type hello in cmd/bash/sh in any directory.

To test it, make sure you are not in the project directory. Open cmd/bash/sh and type hello :

$ hello Hello world

Boom!!! our Node app works globally in our machine!

Publishing our project to NPM

To be able for users to install our node project and use it globally in the machine, we have to push it to NPM.

Before pushing our project, we need to bet or ignore some files or folders, node_modules is the main folder that is usually ignored because when the dependencies in the node_modules will be installed when the users pull in our project.

Since we have not installed any dependencies so we have no node_modules folder, but if to say we have it. To ignore it is easy just create .npmignore file and add the node_modules folder in it.

// .npmignore

node_modules/

We can then push our project to NPM:

npm publish

yarn publish + hello@0.0.1

Users can install our hello project globally:

npm i hello -g

The user can run the hello command in the shell like this:

$ hello Hello world

Adding commands to our project

A node project can have many commands. Our hello project has one shell command hello , we can add many commands to it.

We can add commands like:

sayName : says my name "Nnamdi Chidume" and my details like age , career .

: says my name and my details like , . tip : gives a tip of the day.

: gives a tip of the day. today : prints today's date.

To do that we will edit our package.json

// package.json

{

name: "hello",

// ...

bin: "./index.js"

// ...

} |

|

v // package.json

{

name: "hello",

// ...

bin: {

"hello": "./index.js",

"sayName": "./sayName.js",

"tip": "./tip.js",

"today": "./today.js"

}

// ...

}

The bin property is now an object that holds the command and its corresponding file to call.

Now, let’s create the files:

touch sayName.js

touch tip.js

touch today.js

Then, we flesh them out.

#!/usr/bin/env node

// sayName.js console.log("Im Chidume Nnamdi

")

console.log("I am a Software Developer") #!/usr/bin/env node

// tip.js console.log("Never give up")

console.log("There is light at the end of the tunnel")

#!/usr/bin/env node

// today.js console.log("Today's date is " + Date.now().toLocaleString())

Now our node-cli project folder would look like this:

node-cli

index.js

sayName.js

tip.js

today.js

package.json

.npmignore

Run the npm link to create symlinks for our new commands. You can also publish the new updates to NPM to add the new commands.

After done with that, our users can use our commands as shell commands:

$ hello

Hello world

$ sayName

I'm Chidume Nnamdi

I am a Software Developer

$ tip

Never give up

There is light at the end of the tunnel

$ today

Today's date is Fri 02/07/2019

Conclusion

See we demonstrated how to create a command-line tool in JS using Nodejs. It is very easy, just a couple of tweaks you have your CLI.

I know I didn’t demonstrate with a real-world example, I only explained and demoed how to configure to get your CLI. With the knowledge, create your real-world example and make it a CLI with the tweaks you learned here.

If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me.

Thanks !!!

Related Stories