NestJS is a powerful framework for building efficient and scalable Node.js server-side applications. Typically known for its robust server-side API development capabilities, NestJS can also be leveraged to create useful Command-Line Interface (CLI) tools. This guide will walk you through the steps of creating a CLI tool using NestJS and TypeScript.
Why NestJS for CLI?
NestJS, built with TypeScript, provides out-of-the-box support for TypeScript features and a modular architecture, which is conducive to creating maintainable and scalable CLI applications. Additionally, NestJS leverages IoC (Inversion of Control), making dependency management straightforward.
Setting Up a NestJS Project
First, you need to set up a NestJS project. If you haven’t installed the NestJS CLI yet, you can do so using npm or yarn:
npm i -g @nestjs/cli
# or
yarn global add @nestjs/cli
Create a new project:
nest new cli-tool
Navigate to the project directory:
cd cli-tool
Adding a CLI Command
NestJS doesn’t include a CLI-specific module, but with a little configuration, we can create a command-line tool. We’ll use Commander.js
to handle CLI input. First, install commander
:
npm install commander
# or
yarn add commander
Now, create a new commands
directory in the src
folder, and add a hello.command.ts
file:
import { Command } from 'commander';
import { Injectable } from '@nestjs/common';
@Injectable()
export class HelloCommand {
run(name: string): void {
console.log(`Hello, ${name}! Welcome to your NestJS CLI tool.`);
}
}
// Initialize and configure the command
const helloCommand = new Command()
.name('hello')
.description('Greets the user')
.argument('<name>', 'Name of the user')
.action((name: string) => {
const command = new HelloCommand();
command.run(name);
});
export default helloCommand;
Bootstrapping the CLI
Next, we need to bootstrap the CLI application. Create a cli.ts
file in the src
directory:
import { Command } from 'commander';
import helloCommand from './commands/hello.command';
const program = new Command();
// Configure CLI metadata
program
.name('cli-tool')
.description('A simple CLI tool with NestJS')
.version('1.0.0');
// Add commands
program.addCommand(helloCommand);
// Parse the CLI arguments
program.parse(process.argv);
Running the CLI
For the CLI to execute, modify the package.json
to add a CLI entry point:
{
"name": "cli-tool",
"version": "1.0.0",
"description": "A CLI tool built with NestJS",
"main": "dist/main.js",
"scripts": {
"start": "nest start",
"build": "nest build",
"cli": "ts-node src/cli.ts"
},
// Other configurations...
"bin": {
"cli-tool": "./dist/cli.js"
}
}
To execute the command:
npm run build
npm link # Links the CLI tool globally
cli-tool hello John # Outputs: Hello, John! Welcome to your NestJS CLI tool.
Extending Functionality
The architecture of NestJS allows for easily extending the CLI’s functionality. Create additional commands and services as you see fit. For instance, to add a ‘goodbye’ command:
- Add a new file
goodbye.command.ts
:
import { Command } from 'commander';
import { Injectable } from '@nestjs/common';
@Injectable()
export class GoodbyeCommand {
run(name: string): void {
console.log(`Goodbye, ${name}!`);
}
}
const goodbyeCommand = new Command()
.name('goodbye')
.description('Says goodbye to the user')
.argument('<name>', 'Name of the user')
.action((name: string) => {
const command = new GoodbyeCommand();
command.run(name);
});
export default goodbyeCommand;
- Update
cli.ts
to include the new command:
import { Command } from 'commander';
import helloCommand from './commands/hello.command';
import goodbyeCommand from './commands/goodbye.command';
const program = new Command();
program
.name('cli-tool')
.description('A simple CLI tool with NestJS')
.version('1.0.0');
program.addCommand(helloCommand);
program.addCommand(goodbyeCommand);
program.parse(process.argv);
Conclusion
You’ve now created a basic CLI tool using NestJS and TypeScript. While NestJS isn’t traditionally used for CLI tools, its modular and robust design makes it quite suitable for the task. From here, you can explore more advanced features such as complex argument parsing, dependency injection for more extensive functionalities, and more sophisticated commands.
Happy coding!