Yargs examples

Table of contents

Yargs is a Node package that parses arguments and generates help menus for your CLI tools. In this post, you’ll see how to configure Yargs to accomplish those tasks with examples. But before we see the examples, it will be useful to explain some CLI terms first.

CLI Terms

Commands and options

CLI tools accept two types of arguments: commands and options.

  • The commands are arguments that don’t have a hyphen (-) in front of them. For example, git clone or git init; clone and init are two different git commands. Use commands if your program is big and performs a wide range of tasks. If your program performs only a specific task, you don’t need commands.
  • The options, on the other hand, are prefixed with hyphens. With two hyphens you indicate the full name of the option: e.g.--verbose and with one the alias: e.g.-v. Use options to get input from the user and customize the behavior of the program.

Node shebang

Add this at the top of your file:

#!/usr/bin/env node

I will not attempt to explain what a shebang is—I didn’t find a good, non-technical explanation—but, instead, I will tell you what it does. It locates the node executable and allows you to run the script as a binary in Unix systems. For example, you can run the program with ./scipt.js instead of node script.js. There’s also an ESLint rule for the correct usage of shebang.

bin field in package.json

Use package.json’s bin field to provide aliases for your scripts. You can then use those aliases to call your scripts after you install your package globally. You can install your package globally by running npm link or by publishing it. Consider the following package.json:

package.json
{
  "name": "calculate-stuff",
  "bin": {
    "area": "./area.js",
    "circle-area": "./circle-area.js"
  }
}
// Install it globally with `npm link`.
// Run it with `area --width 10 --height 5` or with `circle-area --radius 5`

By specifying the bin fields, you can now call the area script with:

area --width num --height num

and the circle-area script with:

circle-area --radius num

If you don’t provide aliases, you have to call the index script with calculate-stuff and figure out what to do from there.

Special characters

When working with command-line tools, you may encounter some special characters:

  • The argument is required: <argument>.
  • This argument is optional: [argument].
  • Use the pipe operator for name/alias: <name|alias>.
  • You indicate an array with an ellipsis [arguments…].

Resources (kind of):

Configure an option

Let’s assume that you want to write a program that gets from the user the width and the height of a rectangle, calculates the area, and prints the result in the console:

area.js
// Get the arguments from somewhere.
const { width, height } = getArguments();
console.log(`The area is ${width * height}`);

You can use Yargs to get the width and height arguments from the user and create a help menu. Calculating the area of a rectangle is a trivial task, but the point is to see how to configure Yargs to parse options and create help menus.

You can start by requiring Yargs. By doing that, you now have access to the arguments.

area.js
#!/usr/bin/env node
var { argv } = require("yargs");
console.log(argv);

If you now call the program with:

node area.js --message=hello

or, thanks to the shebang, with:

./area.js --message=hello

The program will log the following object in the console:

{ _: [], message: 'hello', '$0': 'area.js' }

This is already useful but let’s configure it further. You can add the name of the program the user sees when they open the help menu with the scriptName method. A user can see the help menu by calling the program with the --help option.

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area");

You can teach the user how to use your tool when they request the help menu. To do that, you can display a helpful message with the usage method. The $0 will be replaced by the script (program) name.

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num");

You can also show an example of how to use your tool in the help menu with the example method. With the first parameter you specify what user has to type in the console, and with the second what the program should print:

area.js
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  );

Let’s now start configuring some options. You’ll configure the width (-w) option with the option method. This method takes the option name as the first parameter and a configuration object as the second. You can find all the valid configuration options in the Yargs API page.

The first thing you can do is to add the --width as an alias for the -w option. To do that, you define the alias property of the configuration object:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    // The alias of -w is --width.
    alias: "width",
  });

You can show a help menu message for the width option with the describe property. This message will show up when the user asks for the help menu:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
  });

You can make the width option required and show an error message when the user forgets to provide it:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
  });

An alternative is to use a default value with the default property instead of requiring the option. For example, you can add the number 5 as the default value for the width with default: 5.

You can provide a type for the option with the type property:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
    type: "number",
  });

Instead of using the type property, you can also use the number property. For example, you can say that number: true. Other type options you can choose from are the boolean, array, and string.

Finally, you can say how many numbers you expect after the width option with the nargs property. In this example, you only want one, so you can express that with: nargs: 1. If the user calls the program with -w 10 11, only the first value (10) will be assigned to the width:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
    type: "number",
    nargs: 1,
  });

And that’s it for the width option. You can now do something similar for the height option:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
    type: "number",
    nargs: 1,
  })
  .option("h", {
    alias: "height",
    describe: "The height of the area.",
    demandOption: "The height is required.",
    type: "number",
    nargs: 1,
  });

Instead of using the option method, you can use the individual methods to configure the options. One of those methods is the describe method. In the following snippet, I’m using the describe method to override the message of the --help and --version options. More about the individual methods in a bit:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
    type: "number",
    nargs: 1,
  })
  .option("h", {
    alias: "height",
    describe: "The height of the area.",
    demandOption: "The height is required.",
    type: "number",
    nargs: 1,
  })
  .describe("help", "Show help.") // Override --help usage message.
  .describe("version", "Show version number."); // Override --version usage message.

Finally, you can use the epilog method to print a message at the end of the help menu. In the following example, I show some copyright information.

If everything goes well, you can get the width and height options and print the result in the console:

area.js
#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
    type: "number",
    nargs: 1,
  })
  .option("h", {
    alias: "height",
    describe: "The height of the area.",
    demandOption: "The height is required.",
    type: "number",
    nargs: 1,
  })
  .describe("help", "Show help.") // Override --help usage message.
  .describe("version", "Show version number.") // Override --version usage message.
  .epilog("copyright 2019");

const { width, height } = argv;

console.log(`The area is ${width * height}`);

In the following snippet, you can see what the program prints in the console if you call it with the --help option:

./area.js --help

# Usage: area -w num -h num
#
# Options:
#   --help        Show help.                     [boolean]
#   --version     Show version number.           [boolean]
#   -w, --width   The width of the area.         [number] [required]
#   -h, --height  The height of the area.        [number] [required]
#
# Examples:
#   area -w 5 -h 6  Returns the area (30) by multiplying
#                   the width with the height.
#
# copyright 2019

This is the output if you call it without the --width and --height arguments:

node area.js

# Usage: area -w num -h num
#
# Options:
#   --help        Show help.                     [boolean]
#   --version     Show version number.           [boolean]
#   -w, --width   The width of the area.         [number] [required]
#   -h, --height  The height of the area.        [number] [required]
#
# Examples:
#   area -w 5 -h 6  Returns the area (30) by multiplying
#                   the width with the height.
#
# copyright 2019
#
# Missing required arguments: w, h
# The width is required.
# The height is required.

Use the individual methods

Instead of using the option method, you can use the individual methods. For example, the configuration for the --width option can be written as shown below:

#!/usr/bin/env node
// area.js
var { argv } = require("yargs")
  // ...
  .alias("w", "width")
  .describe("w", "The width of the area.")
  .demandOption("w", "The width is required.")
  // .default("w", 5)
  .number("w")
  .nargs(1)
  .alias("h", "height")
  .describe("h", "The height of the area.")
  .demandOption("h", "The height is required.")
  // .default("h", 5)
  .number("h")
  .nargs(1);
// ...

Run the program

You can now run the program in the following ways:

  • ./area.js -w 5 -h 6, if you add the node shebang at the top of the file.
  • node area.js -w 5 -h 6.
  • npm link to install it globally, and then area -w 5 -h 6—replace the area with the name you set up in the bin field of your package.json.

Other interesting configuration options

  • .implies(). implies('w', 'h') means that if -w has a value, then -h should have a value too. It could be useful in our case because the program needs both options to calculate the area.
  • .strict(). Throws errors if the options/command requirements are not met. For example, if the type of an option is not correct, it throws an error.
  • Dealing with quotes

Commands

I don’t need it right now, maybe I will revisit it in the future. For now, see Advanced in Yargs docs.

See the Yargs GitHub page.

Other things to read

Popular

Previous/Next