I recently started a role on a company’s developer experience team. One of the responsibilities that comes along with this is building larger CLI applications. As I , I use the library when writing scripts for my NodeJS projects. This is great for smaller utilities that only a couple of people will use, but what about if it needs to interact with multiple services and have lots of nested commands? wrote previously commander DevOps As it turns out, NestJS supports this using the same commander library that I used previously. In this article, I’ll show you how to create a basic CLI using this setup. Creating the Project Creating the CLI project is the same as creating an API with NestJS. Simply follow the . basic workflow on nestjs website npm i -g @nestjs/cli nest new my-cli-project cd my-cli-project Setup nest-commander The library provides all the code that you’ll need to create your commander CLI in the background. Like every other node dependency, the first step is to install the package. nest-commander npm i nest-commander Creating a Command Just like with normal , we need to create a module that our command will live in. nestjs development Nest-Commander provides . I’ve tried using them but wasn’t able to get them to work. You may have better luck, but I’ll continue with the manual process. some tools that plug into the nest cli nest g module CowSay Normally, you would create a controller or resolver in your module using the nest cli. Since we’re creating a cli, we want to create a instead. Create a file in the folder and open it. Command cow-say.command.ts src/cow-say Each command that you create will extend the class and use the decorator. In the file that you just created, add the following. CommandRunner @Command() cow-say.command.ts import { Command, CommandRunner } from 'nest-commander'; @Command({ name: 'cowsay', options: { isDefault: true, }, }) export class CowSayCommand extends CommandRunner { async run(): Promise<void> { } } To get this command to display something, import the library. cowsay import * as cowsay from 'cowsay'; You’ll need to install it too… npm i cowsay …and update the method in run cow-say.command.ts async run(): Promise<void> { console.log(cowsay.say({ text: 'Hello World!' })); } Wiring Everything Together Now that the command is created, you need to register it as part of the module. Open the file and add as a provider. cow-say.module.ts CowSayCommand import { Module } from '@nestjs/common'; import { CowSayCommand } from './cow-say.command'; @Module({ providers: [CowSayCommand], }) export class CowSayModule {} Tell NestJS that it’s not a server Now comes the tricky part. The nest project that you created is set up to create a REST API by default, but you don’t need that. So, delete the app service and controller. rm app.service.ts rm app.controller.ts Next, update the to import the module. AppModule CowSay import { Module } from '@nestjs/common'; import { CowSayModule } from './cow-say/cow-say.module'; @Module({ imports: [CowSayModule], }) export class AppModule {} Finally, you need to update the file. You’ll change the function to use instead of . main.ts bootstrap CommandFactory NestFactory import { CommandFactory } from 'nest-commander'; import { AppModule } from './app.module'; async function bootstrap() { await CommandFactory.run(AppModule); } bootstrap(); Running It I like to have the option of running my CLI tools without having to run a TypeScript build step. This helps speed up development. To run your CLI without building it, you’ll be using the package. To get started, install it as a development dependency. ts-node npm i -D ts-node Now, add a new script to package.json "start:cli": "ts-node src/main.ts" …and you can test your CLI by running the script ❯ npm run start:cli > my-cli-project@0.0.1 start:cli > ts-node src/main.ts ______________ < Hello World! > -------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || Summary This article showed how to get started building your very first NestJS CLI application. Taking this approach can help you build a larger application that is maintainable. In future articles, I’ll be introducing you to more advanced features of this setup. Also published . here