CLI module for Node.js

My go-to node modules for basic command line argument parsing.

I've heard oclif is great for creating command line tools. At some point I want to give it a spin. But looking at the Getting Started section of their docs, it seems like it would be using a shotgun to kill a fly in the context of the little scripts and simple use cases that I have for making quick command line interfaces.

Most of the time I'm looking for something that offers basic command line argument parsing.

In this case, I tend to reach for the cli node module, which is what the xdpm CLI uses (where I first learned about the module).

A couple of recent examples where I'm using cli for some smaller scripts...

Example 1

First, the ridiculous example!

The other day I mentioned that I created a tiny Shelves CLI. This was of course nothing more than a way to use writing JavaScript to procrastinate on hanging some shelves.

But this little toy CLI does happen to demonstrate how simple it can be to take in structured command line arguments with the cli module.

Here's the code for getting command line arguments in that script:

#!/usr/bin/env node
const cli = require("cli");
cli.enable("version");

const args = cli.parse({
  wallWidth: ["w", "Wall width", "int", 82.5],
  shelfWidth: ["s", "Shelf width", "int", 36],
  shelfCount: ["c", "Shelf count", "int", 2],
  bracketPadding: [
    "p",
    "Padding between the edge of the shelf and the center of the bracket",
    "int",
    5,
  ],
});

const { wallWidth, shelfWidth, shelfCount, bracketPadding } = args;

// etc etc

So I can run this script by, say, setting the wall width and keeping all the other defaults:

% ./index.js -w 100
[ { '1': 21, '2': 47 }, { '1': 73, '2': 99 } ]

In this case, on the last line of the script above, wallWidth would be 100 and all of the other deconstructed variables would retain the default values defined in the object passed to cli.parse().

This is not much code at all for getting the flexibility of a command line interface.

Example 2

This example really won't be significantly different from the first example. But as another way to show the cli module in action, here's the top of a script I'm currently writing to analyze integrations review metrics for a couple of marketplaces:

#!/usr/bin/env node
const cli = require("cli");
cli.enable("status", "version");

const options = {
  marketplace: ["p", "The marketplace", "string", "xd"],
  dayCount: ["d", "Number of days back", "int", 30],
};

const cliOptions = cli.parse(options);

require("./src")(cliOptions);

I could run this script by doing:

% ./index.js -d 60

Which would result in the following cliOptions object:

{
  marketplace: "xd", // The default defined in `options` above
  dayCount: 60, // The value passed in from the command line
}

After that, I'm just passing those options to src/index.js where the real fun begins.

Again, not a lot of code for this added flexibility.


I'm sure there are pleeeeeenty of options in Node.js land for creating CLIs. But cli is worth your consideration if you're looking for something lightweight, simple, and no-fuss.

At some point, I want to give oclif a spin to see how it compares.