Terminal task list reborn! Create beautiful CLI interfaces via easy and logical to implement task lists that feel alive and interactive.
listr2 is a TypeScript-first library for creating interactive, hierarchical task lists in Node.js CLI applications. It renders live progress indicators, spinners, and task statuses directly in the terminal, replacing static console.log statements with dynamic, user-friendly interfaces. The library evolved as a complete rewrite of the original Listr, addressing architectural limitations while adding concurrent execution, advanced error handling, and extensible renderer systems.
With over 29 million weekly downloads, listr2 powers build tools, deployment scripts, and development workflows across projects like Angular CLI, Cypress, and Electron. Its core abstraction—the Listr class—accepts task arrays with async executors, titles, and shared context objects. Tasks execute sequentially or concurrently, with built-in support for retries, conditional skipping, rollbacks, and subtask hierarchies. Five built-in renderers adapt output to different environments: default animated views for interactive terminals, verbose logging for CI/CD, and silent modes for headless automation.
The library's TypeScript-native design (98% TS codebase) provides full type safety for task definitions, context objects, and renderer options. Developers can integrate prompts via adapter packages (@listr2/prompt-adapter-enquirer, @listr2/prompt-adapter-inquirer) for interactive CLI workflows. While the ~269kB bundle size isn't suitable for minimal CLIs, listr2 excels in complex scenarios requiring structured task orchestration with real-time feedback.
Compared to simpler alternatives like ora (spinner-only) or cli-progress (basic bars), listr2 offers comprehensive task lifecycle management, nested structures, and production-grade error handling. It trades simplicity for power—ideal when your CLI needs to coordinate multiple async operations with clear visual feedback rather than just showing a single loading spinner.
import { Listr } from 'listr2';
import { readFile, writeFile } from 'fs/promises';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
interface Ctx {
version: string;
filesProcessed: number;
}
const tasks = new Listr<Ctx>([
{
title: 'Reading package.json',
task: async (ctx) => {
const content = await readFile('package.json', 'utf-8');
ctx.version = JSON.parse(content).version;
}
},
{
title: 'Running tests',
task: () => execAsync('npm test'),
retry: 2
},
{
title: 'Building project',
task: (ctx, task) => {
return task.newListr([
{
title: 'Transpiling TypeScript',
task: async () => {
await execAsync('tsc');
}
},
{
title: 'Bundling assets',
task: async (ctx) => {
await new Promise(resolve => setTimeout(resolve, 1500));
ctx.filesProcessed = 42;
}
}
], { concurrent: false });
}
},
{
title: 'Creating release tag',
skip: (ctx) => ctx.version === '0.0.1' ? 'Skipping initial version' : false,
task: async (ctx) => {
await execAsync(`git tag v${ctx.version}`);
}
}
], {
concurrent: false,
exitOnError: true
});
tasks.run({ filesProcessed: 0 } as Ctx)
.then((ctx) => {
console.log(`\nBuild completed! Version: ${ctx.version}, Files: ${ctx.filesProcessed}`);
})
.catch((err) => {
console.error('Build failed:', err.message);
});Build and deployment pipelines: Orchestrate multi-step processes like dependency installation, asset compilation, test execution, and remote deployment. Each step renders as a task with real-time status updates, error indicators, and optional retry logic for flaky network operations.
Database migration scripts: Execute sequential schema changes, data transformations, and validation checks. Nested subtasks show granular progress (e.g., "Migrating users table" → "Copying data", "Creating indexes", "Validating constraints"), with automatic rollback on failure.
Development tooling and scaffolding: Power CLI generators (like create-react-app or Nx) that clone templates, install dependencies, initialize git repositories, and run initial builds. Concurrent task execution speeds up parallel operations like npm install and file copying.
System health checks and diagnostics: Run parallel service connectivity tests, API endpoint validation, and dependency version checks. The concurrent renderer displays multiple simultaneous operations, clearly marking passed/failed checks with colored indicators.
Data processing workflows: Coordinate ETL jobs that fetch external data, transform records, validate outputs, and upload results. Long-running tasks benefit from output streaming (task.output() updates) and progress indicators for batch operations.
npm install listr2pnpm add listr2bun add listr2