mrkeyoor.com_
Sun 20 Sept 11:47 UTC
npmCLI & Toolingupdated 20 Sept 2026

inquirer review

inquirer 14.1.0 runs the repository's legacy question-object interface for interactive Node command lines. A prompt session accepts questions with names, messages, defaults, conditions, validators, filters, and choice providers, then resolves an answers object. Built-in types cover text, number, confirmation, select lists, raw lists, expand menus, checkboxes, passwords, editor input, and search. The current release updates the included prompt suite to 8.6.0 and core to 12.0.0. That brings a prefilled `initialValue` to search, fixes floating-point number steps and explicit `undefined` defaults, and changes the core `useState` setter type used by custom prompt authors.

34.5Mdownloads / wk
Verdict

inquirer 14.1.0 installed in 2.1 seconds and left 27 packages using 2 MB in our sandbox, but its browser build failed and its own README labels the API legacy. Keep it for existing question arrays and older plugins; start new prompt flows with `@inquirer/prompts`.

We installed it

Lab card: what happened when we installed inquirerScreenshot of inquirer documentation
Install✓ · 2.1s27 packages on disk · 2 MB
ImportESM import works · require() works · ESM package with exports map
Browsern/acould not be bundled for the browser (Node-only code, most likely)
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does inquirer install cleanly?

Yes. In a fresh container with an empty cache, npm install inquirer finished in 2 seconds, leaving 27 packages and 2 MB on disk. npm audit reported no known vulnerabilities.

Can inquirer run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does inquirer work with both ESM and CommonJS?

Yes. Both import 'inquirer' and require('inquirer') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does inquirer include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

inquirer or @inquirer/prompts: which should you use?

@inquirer/prompts: Choose the repository's current function-based API for new commands and import only the prompt functions you call. inquirer 14.1.0 installed in 2.1 seconds and left 27 packages using 2 MB in our sandbox, but its browser build failed and its own README labels the API legacy.

When should you not use inquirer?

You are designing a new CLI. The package's own README calls this interface legacy and directs new work to @inquirer/prompts.

API stability4/5The familiar `prompt(questions, answers)` session still supports the same question names, conditions, defaults, validators, filters, choice objects, plugin registration, and reactive input model. Version 14.1.0 does introduce a type-level break beneath that surface: `@inquirer/core` 12 allows updater functions in `useState` setters. Built-in prompts are unaffected according to the release notes, but custom prompts using the core hooks need a compile and behavior check.
Docs4/5The package-specific README plainly marks this API as legacy, enumerates every question property and built-in type, explains asynchronous callbacks, documents TTY rejection, and includes reactive and editor behavior. That is enough to maintain an existing flow. Its weakness is split documentation: current search and core features live under separate package READMEs, and old community plugin links do not establish compatibility with 14.1.0.
Maintenance4/5npm published 14.1.0 on August 19, 2026, and GitHub shows a push on August 25, 2026, 21,615 stars, 18 open issues and pull requests, and an unarchived repository. The release incorporates active work from the scoped prompt packages, including number fixes and search input initialization. The legacy facade receives maintenance rather than new interface design, which the maintainers state directly in its README.
Ecosystem5/5npm counted 49,856,475 downloads from August 19 through August 25, 2026, while GitHub reports 21,615 stars. Yeoman-era generators and many mature CLIs still use the question-object contract, and its plugin registry is the main reason to preserve it. The monorepo also offers a practical migration route because `inquirer` and `@inquirer/prompts` can coexist as individual command flows are replaced.

Discussed on

  1. hnPhilly courts will ban all smart eyeglasses starting next week416 points
  2. hnPirate Bay founder is being held in solitary confinement without a warrant343 points
  3. hnMail delays hit Philadelphia residents, short staffed USPS struggles to keep up330 points
  4. hnUS claims all .com and .net websites are in its jurisdiction253 points
  5. hnWhy we’re removing comments on most of Inquirer.com224 points

Use it if

  • An established CLI already has question arrays built around `when`, `validate`, `filter`, and one shared answers object.
  • A migration must keep old `registerPrompt()` plugins working while newer command paths move to scoped prompt functions.
  • Questions are produced over time through the documented RxJS-compatible observable interface.
  • One session needs several legacy prompt types and prefilled answers from flags or a config file.
Skip it if

Setup reality

We installed inquirer 14.1.0 in a fresh Node 22 Bookworm container in 2.1 seconds. It left 27 packages and 2 MB on disk. The published package is 100 KB unpacked, declares 6 direct dependencies and 1 peer dependency, and bundles TypeScript declarations. npm audit found 0 known vulnerabilities. It identifies itself as ESM and has an exports map, yet both ESM import and require() loaded successfully in our sandbox.

Node patch level is an early failure point: 14.1.0 requires >=23.5.0, ^22.13.0, or ^20.17.0. There are no credentials or project configuration files, but there must be an interactive terminal. CI, redirected stdin, and background jobs need a noninteractive path before calling prompt(). Our browser bundle attempt failed, which is consistent with code that controls stdin, stdout, cursor movement, and terminal width.

Terminal ownership causes stranger failures than installation. Pause an existing node:readline interface before Inquirer takes stdin, then resume it afterward. When supplying a custom input stream or piping process.stdin, call setRawMode(true) if arrow keys stop working. Ctrl+C rejects the prompt with ExitPromptError, and a missing TTY rejects with isTtyError; handle both so users do not get a stack trace for an ordinary exit.

The editor type launches $VISUAL, then $EDITOR, then a platform default and waits for a temporary file. Password characters remain visible unless mask is set. Version 14.1.0 also carries @inquirer/core 12, whose state setter accepts updater functions. Built-in questions keep working, but locally authored core prompts should be compiled and exercised before this upgrade.

Patterns

Ask for a name and a boolean collect-basic-answers

import inquirer from 'inquirer'

const answers = await inquirer.prompt([
  { type: 'input', name: 'project', message: 'Project name:' },
  { type: 'confirm', name: 'typescript', message: 'Use TypeScript?', default: true },
])

console.log(answers.project, answers.typescript)

Each `name` becomes a property in the resolved object. A dotted name creates a nested answer path.

Store a value from a list select-one-choice

const { target } = await inquirer.prompt([{
  type: 'list',
  name: 'target',
  message: 'Deployment target:',
  choices: [
    { name: 'Preview environment', value: 'preview', short: 'Preview' },
    { name: 'Production environment', value: 'production', short: 'Production' },
  ],
}])

The menu displays `name`, resolves `value`, and prints `short` after the user confirms a choice.

Return checked task values select-many-choices

const { tasks } = await inquirer.prompt([{
  type: 'checkbox',
  name: 'tasks',
  message: 'Tasks to run:',
  choices: [
    { name: 'Unit tests', value: 'test', checked: true },
    { name: 'Lint', value: 'lint' },
    { name: 'Publish', value: 'publish', disabled: 'release role required' },
  ],
}])

Checkbox answers are arrays. A string-valued `disabled` property blocks the option and explains why.

Ask a follow-up conditionally branch-question-flow

const answers = await inquirer.prompt([
  { type: 'confirm', name: 'deploy', message: 'Deploy this build?', default: false },
  {
    type: 'list',
    name: 'region',
    message: 'Region:',
    choices: ['us-east', 'eu-west'],
    when: ({ deploy }) => deploy,
  },
])

When the `when` function returns false, Inquirer skips the question and omits its name from the answer object.

Validate a port and store a number validate-and-convert

const { port } = await inquirer.prompt([{
  type: 'input',
  name: 'port',
  message: 'Port:',
  validate(value) {
    const n = Number(value)
    return Number.isInteger(n) && n >= 1 && n <= 65535
      ? true
      : 'Enter an integer from 1 to 65535'
  },
  filter: Number,
}])

`validate` checks the typed value first. The value returned by `filter` is what Inquirer stores.

Fetch choices after an earlier answer load-choices-lazily

const answers = await inquirer.prompt([
  { type: 'input', name: 'owner', message: 'Repository owner:' },
  {
    type: 'list',
    name: 'repository',
    message: 'Repository:',
    choices: async ({ owner }) => {
      const names = await listRepositories(owner)
      return names.map((name) => ({ name, value: name }))
    },
  },
])

A choices function receives answers already collected. The current prompt waits for its returned promise.

Search choices with an initial term search-remote-choices

const { packageName } = await inquirer.prompt([{
  type: 'search',
  name: 'packageName',
  message: 'Package:',
  initialValue: 'inquirer',
  source: async (term, { signal }) => {
    if (!term) return []
    const url = `https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(term)}&size=10`
    const data = await (await fetch(url, { signal })).json()
    return data.objects.map(({ package: pkg }) => ({ name: pkg.name, value: pkg.name }))
  },
}])

Version 14.1.0 adds `initialValue` through the included search prompt. Pass its AbortSignal to cancel stale requests as the term changes.

Hide a secret while typing mask-password

const { token } = await inquirer.prompt([{
  type: 'password',
  name: 'token',
  message: 'API token:',
  mask: '*',
  validate: (value) => value ? true : 'A token is required',
}])

The password prompt does not hide characters unless `mask` is supplied. Avoid a default that could be printed back to the terminal.

Skip questions already answered by flags prefill-from-flags

const initial = {}
if (argv.project !== undefined) initial.project = argv.project
if (argv.yes !== undefined) initial.confirmed = argv.yes

const answers = await inquirer.prompt(questions, initial)

The second argument seeds the answer object, and matching questions are skipped unless `askAnswered` is true.

Fail with a useful CI message handle-noninteractive-run

if (!process.stdin.isTTY) {
  throw new Error('Noninteractive run: pass --project and --yes')
}

try {
  await inquirer.prompt(questions)
} catch (error) {
  if (error?.isTtyError) process.exitCode = 2
  else throw error
}

`prompt()` rejects outside an interactive TTY and marks that failure with `isTtyError`. Supply a flag or config path for automation.

Exit cleanly after Ctrl+C handle-user-cancel

try {
  await inquirer.prompt(questions)
} catch (error) {
  if (error instanceof Error && error.name === 'ExitPromptError') {
    process.exitCode = 130
  } else {
    throw error
  }
}

Ctrl+C rejects with an `ExitPromptError`. Catch that name separately so an expected cancellation does not print a stack trace.

Register a plugin on a private prompt module scope-custom-prompt

import inquirer from 'inquirer'
import autocomplete from 'inquirer-autocomplete-prompt'

const prompt = inquirer.createPromptModule()
prompt.registerPrompt('autocomplete', autocomplete)

const answers = await prompt([{
  type: 'autocomplete',
  name: 'packageName',
  message: 'Package:',
  source: searchPackages,
}])

A private module avoids changing the process-wide prompt registry. Verify the plugin explicitly supports this Inquirer major before upgrading.

Alternatives

PackageRegistryPick it when
@inquirer/promptsnpmChoose the repository's current function-based API for new commands and import only the prompt functions you call.
@clack/promptsnpmChoose it for visually grouped command flows, progress tasks, and explicit symbol-based cancellation.
enquirernpmChoose it when a single package with many built-in prompt classes and extension hooks fits the codebase.
promptsnpmChoose it for a smaller question-array API when legacy Inquirer plugins and reactive sessions are unnecessary.

More cli & tooling guides

commander · chalk · typescript · esbuild · yargs · click · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.