Back to Blog
Lesson 14 of the Node.js: Build Your First Server & CLI course
Node.jsAugust 1, 20264 min read

Interactive CLI Prompts: Building Dynamic Tools with Inquirer

Learn how to use Inquirer in Node.js to create interactive CLI prompts, moving beyond static arguments to build professional, user-friendly terminal tools.

Node.jsCLIInquirerInteractiveBackendTerminal
Close-up of an AI-driven chat interface on a computer screen, showcasing modern AI technology.

Previously in this course, we explored handling CLI arguments using process.argv. While that approach is sufficient for simple flags, it becomes cumbersome as your application requirements grow. Today, we’ll upgrade our CLI experience by integrating Inquirer, a powerful library that allows us to create beautiful, interactive menus and forms directly in the terminal.

Why Use Interactive CLI Prompts?

Standard CLI arguments are "fire and forget"—you pass them once and hope for the best. Interactive prompts, however, guide the user through the process. They allow for validation, provide selection lists to prevent typos, and create a more professional "wizard" experience for your users.

Installing Inquirer

Because Inquirer is a third-party package, we need to add it to our project. Ensure you have initialized your project as covered in Initializing Projects with NPM, then run the following in your terminal:

Bash
npm install inquirer

Note: Inquirer 9.x and above is ESM-only. Ensure your package.json includes "type": "module" if you are using modern import syntax, as discussed in CommonJS vs ES Modules.

Creating Your First Interactive Flow

Inquirer works by passing an array of "question" objects to the inquirer.prompt() function. Each object defines the type of input (list, input, confirm, etc.), a name to reference the answer later, and a message to display to the user.

Here is how you implement a basic flow:

JAVASCRIPT
import inquirer from CE9178">'inquirer';

const questions = [
  {
    type: CE9178">'input',
    name: CE9178">'username',
    message: CE9178">'What is your name?',
  },
  {
    type: CE9178">'list',
    name: CE9178">'environment',
    message: CE9178">'Which environment are you deploying to?',
    choices: [CE9178">'Development', CE9178">'Staging', CE9178">'Production'],
  }
];

const answers = await inquirer.prompt(questions);

console.log(CE9178">`Hello, ${answers.username}!`);
console.log(CE9178">`Proceeding to deploy to: ${answers.environment}`);

Handling User Input with Logic

In a real-world scenario, you rarely just print the input back to the user. You typically use the results to trigger other functions. Because inquirer.prompt returns a Promise, we use await to pause execution until the user finishes interacting with the prompt.

Worked Example: A Simple Task CLI

Let's build a small utility that asks a user for a task name and its priority:

JAVASCRIPT
import inquirer from CE9178">'inquirer';

async function runTaskWizard() {
  const answers = await inquirer.prompt([
    {
      type: CE9178">'input',
      name: CE9178">'taskName',
      message: CE9178">'Enter your task description:',
      validate: (input) => input ? true : CE9178">'Task name cannot be empty!'
    },
    {
      type: CE9178">'list',
      name: CE9178">'priority',
      message: CE9178">'Select priority:',
      choices: [CE9178">'Low', CE9178">'Medium', CE9178">'High']
    }
  ]);

  // Logic based on input
  console.log(CE9178">`\nCreating task "${answers.taskName}" with ${answers.priority} priority.`);
}

runTaskWizard();

Hands-on Exercise

Modify the script above to add a confirm prompt type. Before the task is "created," ask the user: "Are you sure you want to proceed?". If they answer false, exit the script without printing the success message.

Hint: A confirm prompt returns a boolean true or false.

Common Pitfalls

  1. Forgetting await: Since inquirer.prompt() is asynchronous, forgetting to await it will result in the code executing the next line immediately, often with an empty answers object.
  2. Versioning Issues: Inquirer changed significantly in version 9.0. Always check your package.json version. If you are using older tutorials, you might see require('inquirer'). If you are using modern ESM, stick to import.
  3. Validation Overkill: Don't make your validation logic too complex inside the prompt object. Keep it simple; perform heavy processing after the input is collected.

FAQ

Q: Can I use Inquirer to build complex forms? A: Yes. You can chain as many objects as you like in the questions array. Inquirer will handle the navigation automatically.

Q: Is Inquirer better than process.argv? A: They serve different purposes. process.argv is great for quick, non-interactive commands (like git commit -m "msg"), while Inquirer is perfect for interactive setup scripts or tools where the user needs guidance.

Q: Can I change the list choices dynamically? A: Yes! The choices property can be a function that returns an array based on previous answers, allowing for conditional logic.

Recap

We’ve learned how to move beyond static command-line arguments by using the Inquirer package to capture rich user input. By combining input, list, and confirm types, you can build interactive CLI tools that are intuitive and robust. Your CLI tools are now significantly more user-friendly.

Up next: We will put these skills to work by building a file management CLI that allows you to list, create, and manipulate files based on user-driven input.

Similar Posts