prompts の使い方 — 軽量で美しいCLI対話プロンプトライブラリ
一言でいうと
prompts は、CLIアプリケーションでユーザーに対話的な入力を求めるための軽量なNode.jsライブラリです。Promise ベースの API で、テキスト入力・数値入力・選択メニューなど多彩なプロンプトタイプを統一的なインターフェースで提供します。
どんな時に使う?
- CLIツールの対話的セットアップ —
create-xxx系のスキャフォールディングツールで、プロジェクト名や設定をユーザーに質問する - バッチ処理の確認ステップ — デプロイスクリプトやマイグレーション実行前に「本当に実行しますか?」と確認を挟む
- 設定ファイルの対話的生成 — 複数の選択肢や入力値を順番に聞いて、設定ファイル(
.envやconfig.json)を生成する
インストール
# npm
npm install prompts
# yarn
yarn add prompts
# pnpm
pnpm add prompts
TypeScript の型定義も別途インストールします。
npm install -D @types/prompts
基本的な使い方
最もシンプルなパターンは、プロンプトオブジェクトを1つ渡して await するだけです。
import prompts from 'prompts';
const response = await prompts({
type: 'text',
name: 'projectName',
message: 'プロジェクト名を入力してください',
initial: 'my-app'
});
console.log(response.projectName); // => "my-app" またはユーザーの入力値
複数の質問を配列で渡すと、順番に質問されます。戻り値は全回答をまとめたオブジェクトです。
import prompts from 'prompts';
const questions: prompts.PromptObject[] = [
{
type: 'text',
name: 'username',
message: 'GitHubユーザー名は?'
},
{
type: 'number',
name: 'age',
message: '年齢は?',
validate: (value: number) => value > 0 ? true : '正の数を入力してください'
},
{
type: 'confirm',
name: 'agreed',
message: '利用規約に同意しますか?',
initial: true
}
];
const response = await prompts(questions);
// => { username: 'terkelg', age: 30, agreed: true }
注意: ユーザーが
Ctrl+CやEscでキャンセルした場合、キャンセルされたプロンプト以降のプロパティは返却オブジェクトに含まれません。
よく使うAPI — prompts の主要機能と使い方
1. テキスト入力(text)
最も基本的な自由入力プロンプトです。
import prompts from 'prompts';
const { name } = await prompts({
type: 'text',
name: 'name',
message: 'あなたの名前は?',
initial: '太郎',
validate: (value: string) => value.length === 0 ? '名前を入力してください' : true
});
2. 選択(select / multiselect)
単一選択と複数選択のメニューです。
import prompts from 'prompts';
// 単一選択
const { framework } = await prompts({
type: 'select',
name: 'framework',
message: 'フレームワークを選択してください',
choices: [
{ title: 'Next.js', description: 'Reactベースのフルスタック', value: 'next' },
{ title: 'Nuxt', description: 'Vueベースのフルスタック', value: 'nuxt' },
{ title: 'SvelteKit', description: 'Svelteベースのフルスタック', value: 'sveltekit' }
],
initial: 0
});
// 複数選択
const { features } = await prompts({
type: 'multiselect',
name: 'features',
message: '有効にする機能を選択してください',
choices: [
{ title: 'TypeScript', value: 'ts', selected: true },
{ title: 'ESLint', value: 'eslint', selected: true },
{ title: 'Prettier', value: 'prettier' },
{ title: 'Vitest', value: 'vitest' }
]
});
// features => ['ts', 'eslint'] など
3. 確認(confirm)
Yes/No の二択プロンプトです。
import prompts from 'prompts';
const { shouldDeploy } = await prompts({
type: 'confirm',
name: 'shouldDeploy',
message: '本番環境にデプロイしますか?',
initial: false
});
if (!shouldDeploy) {
console.log('デプロイをキャンセルしました');
process.exit(0);
}
4. 動的プロンプト(条件分岐)
type プロパティに関数を渡すと、前の回答に基づいてプロンプトを動的にスキップできます。type が falsy な値を返すとそのプロンプトはスキップされます。
import prompts from 'prompts';
const response = await prompts([
{
type: 'select',
name: 'database',
message: 'データベースを選択してください',
choices: [
{ title: 'PostgreSQL', value: 'postgres' },
{ title: 'MySQL', value: 'mysql' },
{ title: 'SQLite', value: 'sqlite' }
]
},
{
// SQLite以外の場合のみホスト名を聞く
type: (prev: string) => prev !== 'sqlite' ? 'text' : null,
name: 'host',
message: 'データベースホストを入力してください',
initial: 'localhost'
},
{
type: (prev: string, values: Record<string, any>) =>
values.database !== 'sqlite' ? 'number' : null,
name: 'port',
message: 'ポート番号を入力してください',
initial: (prev: string, values: Record<string, any>) =>
values.database === 'postgres' ? 5432 : 3306
}
]);
5. onSubmit / onCancel コールバックと override / inject
プロンプトチェーンの制御やテスト用のユーティリティです。
import prompts from 'prompts';
// onSubmit: 各回答後に呼ばれる。trueを返すとチェーンを中断
const response = await prompts(
[
{ type: 'text', name: 'first', message: '名前は?' },
{ type: 'text', name: 'last', message: '苗字は?' }
],
{
onSubmit: (prompt, answer, answers) => {
console.log(`${prompt.name}: ${answer}`);
// return true; // ここでtrueを返すと残りの質問をスキップ
},
onCancel: (prompt, answers) => {
console.log('キャンセルされました。収集済みの回答:', answers);
return false; // falseを返す(またはundefined)とプロンプトチェーン全体が終了
}
}
);
// override: CLIの引数で事前に回答を渡す(yargsなどと組み合わせ)
import prompts from 'prompts';
prompts.override({ projectName: 'my-app', framework: 'next' });
const response = await prompts([
{ type: 'text', name: 'projectName', message: 'プロジェクト名は?' },
{ type: 'text', name: 'framework', message: 'フレームワークは?' }
]);
// overrideで渡した値があるプロンプトはスキップされる
// => { projectName: 'my-app', framework: 'next' }
// inject: テスト用に回答をプログラム的に注入
import prompts from 'prompts';
prompts.inject(['my-app', 'next']);
const response = await prompts([
{ type: 'text', name: 'projectName', message: 'プロジェクト名は?' },
{ type: 'text', name: 'framework', message: 'フレームワークは?' }
]);
// => { projectName: 'my-app', framework: 'next' }
// Errorインスタンスを注入するとキャンセルをシミュレートできる
prompts.inject([new Error('cancel')]);
類似パッケージとの比較
| 特徴 | prompts | inquirer | enquirer | @clack/prompts |
|---|---|---|---|---|
| 依存パッケージ数 | 少ない(2個) | 多い | 少ない | 少ない |
| バンドルサイズ | 軽量 | 大きめ | 中程度 | 軽量 |
| Promise対応 | ✅ ネイティブ | ✅(v9+はESM) | ✅ | ✅ |
| TypeScript型定義 | @types/prompts | 同梱(v9+) | @types/enquirer | 同梱 |
| プロンプトタイプ数 | 15種類 | 豊富(プラグイン拡張可) | 豊富 | 少なめ(基本に特化) |
| テスト用inject | ✅ inject() | なし(別途モック必要) | なし | なし |
| メンテナンス状況 | 安定(低頻度更新) | 活発(v9でESM化) | 低頻度 | 活発 |
| 見た目の美しさ | ◎ | ○ | ◎ | ◎(スピナー等も統合) |
選定の目安:
- 軽量さ・シンプルさ重視 →
prompts - 豊富なプラグインエコシステム →
inquirer - モダンなUI・スピナー統合 →
@clack/prompts
注意点・Tips
キャンセル時のハンドリングは必須
ユーザーが Ctrl+C でキャンセルすると、未回答のプロパティは返却オブジェクトに含まれません。これを考慮しないとランタイムエラーの原因になります。
const response = await prompts({
type: 'text',
name: 'name',
message: '名前は?'
});
// キャンセルされた場合 response.name は undefined
if (!response.name) {
console.log('入力がキャンセルされました');
process.exit(1);
}
ESM環境での import
prompts は CommonJS パッケージです。ESM("type": "module")環境では、デフォルトインポートが正しく動作しない場合があります。
// うまくいかない場合
import prompts from 'prompts';
// 以下を試す
import prompts from 'prompts';
// もしくは
const prompts = (await import('prompts')).default;
validate の戻り値
validate 関数は true を返すと検証成功、文字列を返すとその文字列がエラーメッセージとして表示されます。false を返すとデフォルトのエラーメッセージが表示されます。
{
type: 'text',
name: 'email',
message: 'メールアドレスは?',
validate: (value: string) => {
if (!value.includes('@')) return 'メールアドレスの形式が正しくありません';
return true; // ← false ではなく true を返す
}
}
CI環境での自動応答
CI/CD パイプラインでは対話プロンプトが止まってしまいます。override や inject を使って自動応答させましょう。
if (process.env.CI) {
prompts.override({
projectName: 'default-app',
shouldContinue: true
});
}
autocomplete タイプの活用
選択肢が多い場合は autocomplete タイプが便利です。ユーザーが文字を入力すると候補が絞り込まれます。
const { timezone } = await prompts({
type: 'autocomplete',
name: 'timezone',
message: 'タイムゾーンを選択してください',
choices: [
{ title: 'Asia/Tokyo', value: 'Asia/Tokyo' },
{ title: 'America/New_York', value: 'America/New_York' },
{ title: 'Europe/London', value: 'Europe/London' },
// ... 多数の選択肢
],
suggest: (input: string, choices: prompts.Choice[]) =>
choices.filter(c => c.title.toLowerCase().includes(input.toLowerCase()))
});
まとめ
prompts は、依存が少なく軽量でありながら、15種類のプロンプトタイプと動的な条件分岐をサポートする実用的なCLIプロンプトライブラリです。Promise ベースの統一的なAPIと inject によるテスタビリティの高さが特徴で、CLIツール開発の定番選択肢として安心して使えます。より新しいUIが必要な場合は @clack/prompts