commander の使い方 — Node.js CLIツール開発の定番パッケージ
一言でいうと
commander は、Node.js でコマンドラインツール(CLI)を構築するためのフレームワークです。コマンド、オプション、引数の定義・パース・ヘルプ生成をすべて一括で処理してくれます。
どんな時に使う?
- 自作CLIツールの開発 —
mycli init --template reactのようなコマンド体系を持つツールを作りたいとき - 複数サブコマンドを持つCLI —
gitのように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" が完了しました
類似パッケージとの比較
| 特徴 | commander | yargs | cac | clipanion |
|---|---|---|---|---|
| GitHub Stars | ★ 27k+ | ★ 11k+ | ★ 2.5k+ | ★ 1k+ |
| バンドルサイズ | 小さい | やや大きい | 非常に小さい | 中程度 |
| TypeScript対応 | ◎ 型同梱 | ◎ 型同梱 | ◎ 型同梱 | ◎ TS-first |
| サブコマンド | ◎ | ◎ | ○ | ◎ |
| 自動ヘルプ生成 | ◎ | ◎ | ○ | ◎ |
| 学習コスト | 低い | やや高い | 低い | やや高い |
| 設計思想 | メソッドチェーン | 宣言的 | 軽量・シンプル | クラスベース |
| 代表的な採用例 | webpack CLI, Vue CLI, create-react-app | mocha, webpack-cli (旧) | Vite, Vitest | Yarn 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- プレフィックスを付けると、デフォルト true を false にするオプションが作れます。
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 の型定義も同梱されているので、型安全な開発がすぐに始められます。