commander の使い方

the complete solution for node.js command-line programs

v14.0.3/週MITCLI
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

commander の使い方 — Node.js CLIツール開発の定番パッケージ

一言でいうと

commander は、Node.js でコマンドラインツール(CLI)を構築するためのフレームワークです。コマンド、オプション、引数の定義・パース・ヘルプ生成をすべて一括で処理してくれます。


どんな時に使う?

  • 自作CLIツールの開発mycli init --template react のようなコマンド体系を持つツールを作りたいとき
  • 複数サブコマンドを持つCLIgit のように commit, push, pull など複数のサブコマンドを定義したいとき
  • スクリプトの引数パース — 運用スクリプトにオプション(--dry-run, --verbose など)を持たせて安全に実行したいとき

インストール

# npm
npm install commander

# yarn
yarn add commander

# pnpm
pnpm add commander

型定義は本体に同梱されているため、@types/commander は不要です。


基本的な使い方

最もシンプルなCLIの例です。

// cli.ts
import { program } from 'commander';

program
  .name('greet')
  .description('挨拶を表示するCLIツール')
  .version('1.0.0');

program
  .argument('<name>', '挨拶する相手の名前')
  .option('-l, --lang <language>', '言語を指定', 'ja')
  .action((name: string, options: { lang: string }) => {
    if (options.lang === 'en') {
      console.log(`Hello, ${name}!`);
    } else {
      console.log(`こんにちは、${name}さん!`);
    }
  });

program.parse();
$ npx tsx cli.ts World --lang en
Hello, World!

$ npx tsx cli.ts 太郎
こんにちは、太郎さん!

$ npx tsx cli.ts --help
Usage: greet [options] <name>

挨拶を表示するCLIツール

Arguments:
  name                    挨拶する相手の名前

Options:
  -V, --version           output the version number
  -l, --lang <language>   言語を指定 (default: "ja")
  -h, --help              display help for command

よく使うAPI

1. .option() — オプションの定義

import { program } from 'commander';

program
  // 真偽値フラグ(値を取らない)
  .option('-d, --debug', 'デバッグモードを有効にする')
  // 必須値付きオプション
  .option('-p, --port <number>', 'ポート番号', '3000')
  // 任意値付きオプション
  .option('-c, --config [path]', '設定ファイルのパス')
  // カスタムパーサー(数値変換)
  .option('-r, --retry <count>', 'リトライ回数', (val: string) => parseInt(val, 10), 3);

program.parse();

const opts = program.opts<{
  debug?: boolean;
  port: string;
  config?: string | boolean;
  retry: number;
}>();

console.log(opts);

<value> は必須、[value] は任意を意味します。第3引数にパース関数、第4引数(またはパース関数がない場合は第3引数)にデフォルト値を指定できます。

2. .command() — サブコマンドの定義

import { program } from 'commander';

program
  .name('todo')
  .description('TODOリスト管理CLI');

program
  .command('add')
  .description('タスクを追加する')
  .argument('<title>', 'タスクのタイトル')
  .option('--priority <level>', '優先度 (low|medium|high)', 'medium')
  .action((title: string, options: { priority: string }) => {
    console.log(`タスク追加: "${title}" (優先度: ${options.priority})`);
  });

program
  .command('list')
  .description('タスク一覧を表示する')
  .option('--all', '完了済みも含めて表示')
  .action((options: { all?: boolean }) => {
    console.log(`タスク一覧を表示${options.all ? '(全件)' : ''}`);
  });

program
  .command('done')
  .description('タスクを完了にする')
  .argument('<id>', 'タスクID')
  .action((id: string) => {
    console.log(`タスク ${id} を完了にしました`);
  });

program.parse();
$ npx tsx cli.ts add "記事を書く" --priority high
タスク追加: "記事を書く" (優先度: high)

$ npx tsx cli.ts list --all
タスク一覧を表示(全件)

3. .argument() — 位置引数の定義

import { program } from 'commander';

program
  .command('deploy')
  // 必須引数
  .argument('<environment>', 'デプロイ先 (staging|production)')
  // 任意引数
  .argument('[tag]', 'デプロイするタグ', 'latest')
  // 可変長引数(残り全部を配列で受け取る)
  .argument('[services...]', '対象サービス')
  .action((env: string, tag: string, services: string[]) => {
    console.log(`環境: ${env}`);
    console.log(`タグ: ${tag}`);
    console.log(`サービス: ${services.length > 0 ? services.join(', ') : '全て'}`);
  });

program.parse();
$ npx tsx cli.ts deploy production v2.1.0 api web
環境: production
タグ: v2.1.0
サービス: api, web

4. .requiredOption() — 必須オプション

import { program } from 'commander';

program
  .requiredOption('-t, --token <token>', 'APIトークン(必須)')
  .option('-e, --endpoint <url>', 'APIエンドポイント', 'https://api.example.com')
  .action(() => {
    const opts = program.opts<{ token: string; endpoint: string }>();
    console.log(`Token: ${opts.token}`);
    console.log(`Endpoint: ${opts.endpoint}`);
  });

program.parse();
$ npx tsx cli.ts
error: required option '-t, --token <token>' not specified

--token を指定しないとエラーメッセージが表示され、プロセスが終了します。

5. .hook() — ライフサイクルフック

import { program, Command } from 'commander';

// すべてのコマンド実行前に走るフック
program.hook('preAction', (thisCommand: Command) => {
  const opts = thisCommand.opts();
  if (opts.verbose) {
    console.log(`[DEBUG] コマンド "${thisCommand.name()}" を実行します`);
    console.log(`[DEBUG] オプション:`, opts);
  }
});

// コマンド実行後に走るフック
program.hook('postAction', (thisCommand: Command) => {
  const opts = thisCommand.opts();
  if (opts.verbose) {
    console.log(`[DEBUG] コマンド "${thisCommand.name()}" が完了しました`);
  }
});

program
  .option('--verbose', '詳細ログを出力')
  .command('build')
  .description('プロジェクトをビルドする')
  .action(() => {
    console.log('ビルド実行中...');
  });

program.parse();
$ npx tsx cli.ts build --verbose
[DEBUG] コマンド "build" を実行します
[DEBUG] オプション: { verbose: true }
ビルド実行中...
[DEBUG] コマンド "build" が完了しました

類似パッケージとの比較

特徴commanderyargscacclipanion
GitHub Stars★ 27k+★ 11k+★ 2.5k+★ 1k+
バンドルサイズ小さいやや大きい非常に小さい中程度
TypeScript対応◎ 型同梱◎ 型同梱◎ 型同梱◎ TS-first
サブコマンド
自動ヘルプ生成
学習コスト低いやや高い低いやや高い
設計思想メソッドチェーン宣言的軽量・シンプルクラスベース
代表的な採用例webpack CLI, Vue CLI, create-react-appmocha, webpack-cli (旧)Vite, VitestYarn Berry

選定の目安:

  • 迷ったら commander — 最も広く使われており、ドキュメント・事例が豊富
  • 軽量さ重視なら cac — Vite/Vitest が採用しており、APIもシンプル
  • 複雑なCLIをTypeScriptで型安全に作りたいなら clipanion

注意点・Tips

1. program.parse() の呼び忘れに注意

parse() を呼ばないと何も実行されません。ファイル末尾に必ず記述してください。

2. オプション名のキャメルケース変換

--dry-run のようなケバブケースのオプションは、opts() で取得すると自動的に dryRun にキャメルケース変換されます。

program.option('--dry-run', 'ドライラン');
program.parse();

const opts = program.opts<{ dryRun?: boolean }>();
console.log(opts.dryRun); // true

3. 否定オプション(--no-xxx

--no- プレフィックスを付けると、デフォルト truefalse にするオプションが作れます。

program.option('--no-color', 'カラー出力を無効にする');
program.parse();

const opts = program.opts<{ color: boolean }>();
// デフォルト: color = true
// --no-color 指定時: color = false

4. 非同期アクションの扱い

action に async 関数を渡せます。commander は Promise の完了を待ってくれます。

program
  .command('fetch')
  .argument('<url>')
  .action(async (url: string) => {
    const res = await fetch(url);
    const data = await res.json();
    console.log(JSON.stringify(data, null, 2));
  });

program.parse();

5. エラーハンドリングのカスタマイズ

program.exitOverride(); // process.exit() の代わりに例外をスローさせる

try {
  program.parse();
} catch (err: unknown) {
  // CommanderError として捕捉できる
  console.error('CLIエラーをキャッチしました:', err);
  process.exit(1);
}

6. 環境変数からオプションを読み取る

commander 自体には環境変数の自動読み取り機能はありません。デフォルト値に process.env を使うパターンが一般的です。

program.option(
  '-t, --token <token>',
  'APIトークン(環境変数 API_TOKEN でも指定可)',
  process.env.API_TOKEN
);

注意: この記事は commander v14 系を前提としています。v12 以前とはいくつかのAPIに差異がある可能性があります。公式リポジトリの CHANGELOG を確認してください。


まとめ

commander は Node.js CLI 開発における事実上のスタンダードです。オプション定義、サブコマンド、ヘルプ自動生成、引数パースといったCLIに必要な機能が一通り揃っており、学習コストも低いため、初めてのCLIツール開発から大規模なCLIまで幅広く対応できます。TypeScript の型定義も同梱されているので、型安全な開発がすぐに始められます。

比較記事