CLI tool
75lb/command-line-args avatar
75lb/command-line-args

command-line-args: the option parser behind a lot of Node CLIs

A mature, feature-complete library to parse command-line options.

719 stars103 forksJavaScriptMIT

At a glance

What is it?
command-line-args is a Node library that turns a list of option definitions into a parsed object, handling aliases, clustered short flags, repeated values and default options for positional arguments. It is published as an ES module with a CommonJS build, and the README tells upgraders to read the release notes before moving between major versions.
Who is it for?
command-line-args suits a Node command line tool that needs standard option notation handled once rather than reimplemented per project, especially when the tool has aliases, repeatable flags and positional arguments that have to be collected. It does not suit a tool whose main work is generating help output, since the usage guide lives in the separate command-line-usage package, and it does not suit a project that wants zero dependencies.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 36 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One parser, several notations

The library is described as a mature, feature-complete library to parse command-line options, and the pitch is that you set options using the main notation standards, with a wiki page documenting the notation rules in detail.

The example makes the point better than the description does, because four different command lines are shown as equivalent.

code
$ example --verbose --timeout=1000 --src one.js --src two.js
$ example --verbose --timeout 1000 --src one.js two.js
$ example -vt 1000 --src one.js two.js
$ example -vt 1000 one.js two.js

The same values are set whether the long option uses an equals sign, whether the value is separate, whether the short aliases are clustered, and whether the positional values are attached to the option or left on their own. Getting those four forms to agree with each other is precisely the work that a hand written parser gets subtly wrong, and it is the work this library takes on.

The install is a single npm command.

sh
$ npm install command-line-args --save

The package is MIT licensed, the repository carries the copyright line for Lloyd Brookes across 2014 to 2026, and the documentation is generated with jsdoc-to-markdown rather than written by hand, which is why the API reference lives in the doc/ directory of the repository.

Option definitions are the contract you write once

To access the values, you first create a list of option definitions describing the options your application accepts, and the README is explicit that the `type` property is a setter function whose value is passed through, giving you full control over the value received.

js
const optionDefinitions = [
  { name: 'verbose', alias: 'v', type: Boolean },
  { name: 'src', type: String, multiple: true, defaultOption: true },
  { name: 'timeout', alias: 't', type: Number }
]

Three of those properties carry most of the behaviour. The `alias` property binds a short form to a long option, so the -v and -t in the earlier examples resolve to verbose and timeout. The `multiple` property says the option may appear more than once, which is why src collects an array. The `defaultOption` property marks which option receives the values that are not attached to any flag, which is the other half of why `--src one.js two.js` and `--src one.js --src two.js` produce the same result.

The `type` property is where the library gets out of the way. It is a function that receives the raw value and returns the value you want, so Boolean and Number are convenient defaults, and a custom function can validate, coerce or reject a value. The definition list is therefore the single place where the shape of the command line is described, and everything downstream reads from the parsed result.

Parsing returns a plain object

Parsing is one function call with the definitions as its argument.

js
import commandLineArgs from 'command-line-args'
const options = commandLineArgs(optionDefinitions)

The result is a plain object keyed by option name, and the README shows what it looks like for the definitions above.

js
{
  src: [
    'one.js',
    'two.js'
  ],
  verbose: true,
  timeout: 1000
}

Two properties of that object are worth pausing on. The `src` value is an array even though the option was only given once in one of the command lines, because `multiple: true` normalises the shape, so the consuming code does not have to branch on how the user typed it. And `timeout` is the number 1000 rather than the string "1000", because the setter function in the definition did that conversion.

There is a related documentation page on option definitions that the README links, and the library also exposes a lower level API entry point for the cases where the defaults are not what you want. The README does not enumerate every function on that page, so anything beyond the two functions shown here is something to look up in the API reference rather than assume.

Commands and sub-commands are documented, not built in

Beyond the typical usage, the README says you can configure command-line-args to accept more advanced syntax forms, and it does this by pointing at two wiki pages rather than at code in the package.

The first is command-based syntax in the git style, the form `$ executable <command> [options]`.

code
  $ executable <command> [options]

The example given is a git commit with a squash flag and a message.

code
  $ git commit --squash -m "This is my commit message"

The second is command and sub-command syntax in the docker style, the form `$ executable <command> [options] <sub-command> [options]`.

code
  $ executable <command> [options] <sub-command> [options]

And the example is a docker run with detached mode, an image and a command.

code
  $ docker run --detached --image centos bash -c yum install -y httpd

The fact that these are wiki pages titled as implementation guides is the important detail. The npm package is an option parser, and hierarchical command routing is something the README says you can configure, with the walkthrough living outside the repository. Anyone expecting a drop-in argv-style router should read those two pages before choosing the library.

Help text lives in a separate package

A usage guide, typically printed when `--help` is set, can be generated using command-line-usage, and the README points at a separate repository for it. The usage guide is derived from the same option definitions, so the two packages are designed to work together rather than against each other.

Two real examples are shown. The first is a screenshot of a typical usage guide, and the second is the polymer-cli guide, described as a good real-life example.

That division of labour is a real design decision. The parser knows the definitions and the values; the usage generator knows how to lay out a help page, group options, mark defaults and print a synopsis. Keeping them apart means you can use the parser in a tool that never prints help, and it means the help rendering is an opinion you can replace.

The documentation story is the same split. The API reference in the doc/ directory is generated from the source comments with jsdoc-to-markdown, and the package.json shows the exact commands, where the docs script pipes the generator output into doc/API.md and doc/option-definition.md, and the dist script builds the CommonJS bundle. The wiki linked from the README holds the examples and the longer explanations.

ESM entry point, CommonJS build, four dependencies

The package metadata is worth reading because it describes how the library is consumed.

The package is an ES module, with type set to module, and the exports map sends import to ./index.js and require to ./dist/index.cjs. The files published are index.js, lib and dist, and the minimum Node version is 12.20. A consumer on a modern toolchain imports the source entry, and a consumer still on CommonJS gets the built bundle.

There are four runtime dependencies: array-back, find-replace, lodash.camelcase and typical. The presence of a camelCase helper and a type-guessing library tells you something about the intended surface, since option names in a command line are usually written in kebab case and appear in JavaScript as camelCase, and the typical module is the kind of helper that infers a value's type.

There is also a peer dependency on @75lb/nature, marked optional. The nature package appears in the scripts, since the dist and docs commands are run through 75lb-nature, so the peer dependency is a build-time concern rather than a runtime one. The optional peerDependenciesMeta entry says so explicitly.

The test setup is compact. The test script first runs the dist build and then test:ci, which runs test-runner over test/*.js, test/*.cjs and test/internals/*.js, so the suite covers the ES module source, the CommonJS bundle and the internals directory. The whole test run therefore depends on the build succeeding first, which is why dist comes before test in the chain.

Where a dedicated option parser stops being the answer

The first case is a tool with no options to speak of. A script that takes a single positional argument does not need a definitions array, a setter function and a parsed object, and a library that gives you a uniform shape across many option styles is a lot of ceremony for one string.

The second case is a tool whose hard part is the help output rather than the parsing. The usage guide is a separate package, so a project whose main deliverable is a rich help screen, with grouped options, examples and environment variable descriptions, is taking on two packages and the join between them rather than one.

The third case is a project that wants no dependencies at all, which is why the dependency list and the fact that the library is MIT licensed matter to some teams and not to others. Four small packages is not a burden for most, but it is a decision rather than a default.

The alternative worth naming is writing the parsing yourself against process.argv. The difference in approach is that the hand written version has to encode the notation rules yourself, and the notation rules are where the subtlety lives: an equals sign versus a separate value, a clustered short flag, a repeated option, and a value that belongs to no flag. The library's contribution is not that it is clever, it is that those rules are implemented once, consistently, and that the definition list becomes the single description of what your tool accepts. The cost of that convenience is a dependency and, on a major version, behaviour you need to read the release notes about, which is exactly what the README asks upgraders to do.

Editorial conclusion

command-line-args suits a Node command line tool that needs standard option notation handled once rather than reimplemented per project, especially when the tool has aliases, repeatable flags and positional arguments that have to be collected. It does not suit a tool whose main work is generating help output, since the usage guide lives in the separate command-line-usage package, and it does not suit a project that wants zero dependencies. Verify first which major version your dependencies resolve to and read the release notes for it, because the README opens by telling upgraders to do exactly that.

Frequently asked questions

How do I install command-line-args?

With npm install command-line-args --save. The package is MIT licensed, requires Node 12.20 or newer, and is published as an ES module with a CommonJS bundle at ./dist/index.cjs for require.

How do I define the options my Node CLI accepts?

You create a list of option definitions, each an object with a name and optional alias, type, multiple and defaultOption properties. The type property is a setter function, so the value supplied is passed through it, which gives full control over the value received.

What does commandLineArgs return?

A plain object keyed by option name. With the README's example definitions the result holds an array for src because multiple is true, a boolean for verbose and a number for timeout because the type setters converted them.

Does command-line-args handle commands and sub-commands?

The README says the library can be configured to accept more advanced syntax forms and links to wiki pages for command-based syntax in the git style and command and sub-command syntax in the docker style, with $ executable <command> [options] and $ executable <command> [options] <sub-command> [options] as the two forms.

How do I generate a --help guide for a command-line-args project?

The README says a usage guide, typically printed when --help is set, can be generated using the separate command-line-usage package, which is documented in its own repository, with the polymer-cli guide given as a real-life example.

Official sources

  1. 75lb/command-line-args on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/75lb-command-line-args.svg)](https://hysenlabs.com/projects/75lb-command-line-args)

Was this useful?