Skip to content
Back to skills

Commander

ASecurity

Build CLI tools with Commander.js. Use when creating command-line applications, parsing arguments, implementing subcommands, or building developer tools with flags and options.

  • 142 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added May 27, 2026
developmenttypescriptgobashreactnodenodejsgit

Works with

  • terminal
  • cli

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill commander --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Commander?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Commander
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-commander/badge)](https://www.skillsdirectory.com/skills/terminalskills-commander)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: commander
description: >-
  Build CLI tools with Commander.js. Use when creating command-line
  applications, parsing arguments, implementing subcommands, or building
  developer tools with flags and options.
license: Apache-2.0
compatibility: 'Node.js 22.12+ for commander 15; Node.js 20+ for commander 14'
metadata:
  author: terminal-skills
  version: 1.1.0
  category: development
  repository: https://github.com/tj/commander.js
  tags: [commander, cli, nodejs, developer-tools, terminal]
---

# Commander.js

## Overview

Commander is a widely used Node.js library for building command-line tools. It parses arguments and options, defines subcommands, generates `--help` and `--version` output, and reports usage errors with a non-zero exit code. The current release is 15 (May 2026): it is ESM-only and needs Node.js 22.12 or newer, which lets CommonJS code load it with `require()`. Commander 14 supports Node.js 20+.

## Instructions

### Step 1: Install
```bash
npm install commander
# optional, stronger TypeScript inference for opts and action arguments:
npm install @commander-js/extra-typings
```
Use `"type": "module"` in `package.json` (or `.mjs` files) for the `import` syntax below. On Node 20, install `commander@14`.

### Step 2: Basic CLI

```typescript
// src/cli.ts — CLI with commands and options
import { Command } from 'commander'
import { createProject, deploy, confirm } from './actions.js'  // your own code

const program = new Command()
  .name('mytools')
  .description('Developer productivity toolkit')
  .version('1.0.0')

program
  .command('init')
  .description('Initialize a new project')
  .argument('<name>', 'project name')
  .option('-t, --template <type>', 'project template', 'default')
  .option('--no-git', 'skip git initialization')
  .option('-d, --dry-run', 'show what would be created')
  .action(async (name, opts) => {
    console.log(`Creating project: ${name}`)
    console.log(`Template: ${opts.template}`)
    if (opts.dryRun) { console.log('(dry run)'); return }
    await createProject(name, opts)
  })

program
  .command('deploy')
  .description('Deploy to production')
  .option('-e, --env <environment>', 'target environment', 'production')
  .option('--force', 'skip confirmation')
  .action(async (opts) => {
    if (!opts.force) {
      const ok = await confirm(`Deploy to ${opts.env}?`)
      if (!ok) process.exit(0)
    }
    await deploy(opts.env)
  })

await program.parseAsync()
```

Use `parseAsync()` (not `parse()`) when any action is async, so rejected promises propagate. Action handlers receive the declared arguments first, then the options object, then the command: `.action((name, opts, command) => …)`.

### Step 3: Package setup

```json
{
  "name": "mytools",
  "type": "module",
  "bin": { "mytools": "./dist/cli.js" },
  "scripts": {
    "build": "tsc",
    "dev": "tsx src/cli.ts"
  }
}
```
The built `dist/cli.js` needs `#!/usr/bin/env node` as its first line (keep it at the top of `src/cli.ts`).

```bash
npx tsx src/cli.ts init my-project --template react   # development
npm link && mytools deploy --env staging               # after build
mytools --help
```

## Examples

### Example 1: Option rules the user asks about
**Request:** "Make `--env` required and limited to staging or production."

```typescript
import { Command, Option } from 'commander'

new Command('deploy')
  .addOption(new Option('-e, --env <environment>', 'target').choices(['staging', 'production']).makeOptionMandatory())
  .action((opts) => console.log(`deploying to ${opts.env}`))
  .parse(['node', 'mytools', '--env', 'qa'])
```
Result: Commander prints `error: option '-e, --env <environment>' argument 'qa' is invalid. Allowed choices are staging, production.` and exits with code 1.

### Example 2: Variadic arguments and camelCase options
**Request:** "`mytools lint src tests --max-warnings 5` should give me the folders and the number."

```typescript
program
  .command('lint')
  .argument('<folders...>', 'folders to lint')
  .option('--max-warnings <count>', 'allowed warnings', (v) => parseInt(v, 10), 0)
  .action((folders, opts) => {
    console.log(folders, opts.maxWarnings)   // [ 'src', 'tests' ] 5
  })
```
Multi-word flags become camelCase properties (`--max-warnings` becomes `opts.maxWarnings`); the third argument to `.option()` is a parser, the fourth the default.

## Guidelines

- Commander generates `--help` from your definitions; add `.description()` to every command and option.
- Required positionals use `<name>`, optional use `[name]`, a variadic goes last (`<names...>`). Use `.requiredOption()` for mandatory flags.
- `--no-git` alone defines a boolean that defaults to `true` and becomes `false` when passed. In commander 15, defining both `--git` and `--no-git` no longer sets an implicit default; set it yourself if you need one.
- Since commander 14, extra positional arguments are an error by default; call `.allowExcessArguments()` if you want the old behavior.
- Usage errors exit with code 1 automatically. Use `.exitOverride()` to get a `CommanderError` instead of an exit, which helps in tests.
- Subcommands can also live in separate executables (`mytools-deploy`) via `.command('deploy', 'description')`.
- For interactive prompts, pair with `@inquirer/prompts` or `@clack/prompts`.

Files in this skill

  • SKILL.md2.5 KB
  • _scores.json1.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…