Build Your Own CLI Word Counter in Node.js


Have you ever wanted to build your own Command Line Interface (CLI) tool?
In this Blog, I’ll create a simple CLI app in Node.js that counts the number of words in a file. Along the way, we’ll explore how Node.js handles command-line arguments with process.argv
and how to make our CLI professional using the commander library.
Step 1: A Simple Word Counter
Let’s begin with a very basic Node.js program that reads a file and counts words:
const fs = require("fs");
function countWords(fileName) {
fs.readFile(fileName, "utf-8", function (err, data) {
let count = 0;
for (let i = 0; i < data.length; i++) {
if (data[i] == " ") {
count++;
}
}
console.log(count + 1);
});
}
countWords("a.txt");
This works. If a.txt
has text, the script will count its words.
But here’s the problem: this isn’t really a CLI. We can’t do things like node index.js -help
, and it only works with a hardcoded file.
Step 2: Making It Dynamic with process.argv
In Node.js, anything passed after the script name in the command line can be accessed using process.argv
.
console.log(process.argv);
//In console, if you write "node index.js filePath", then the console output will be
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\HarshGupta\\Desktop\\index.js',
'C:\\Users\\HarshGupta\\Desktop\\a.txt'
]
Here:
process.argv[0]
→ path to Node.jsprocess.argv[1]
→ path to our scriptprocess.argv[2]
→ the file path we passed
So, we can make our script dynamic like this:
const fs = require("fs");
function countWords(fileName) {
fs.readFile(fileName, "utf-8", function (err, data) {
let count = 0;
for (let i = 0; i < data.length; i++) {
if (data[i] == " ") {
count++;
}
}
console.log(count + 1);
});
}
countWords(process.argv[2]);
Now we can pass any file path dynamically, but still it doesnt feel like a CLI.
Step 3: Turning It Into a Proper CLI with Commander
To add features like --help
, --version
, and subcommands, we’ll use the commander library.
First install it:
npm install commander
Now, update our code:
const fs = require("fs");
const { Command } = require("commander");
const program = new Command();
program
.name("Counter")
.description("Counts the number of words in a file")
.version("0.0.0");
program
.command("count")
.description("Counts the number of words in a file")
.argument("<file>", "file to count")
.action((fileName) => {
fs.readFile(fileName, "utf-8", (err, data) => {
if (err) {
console.log(err);
} else {
let count = 0;
for (let i = 0; i < data.length; i++) {
if (data[i] == " ") {
count++;
}
}
console.log(`There are ${count + 1} words in ${fileName}`);
}
});
});
program.parse();
Step 4: Running the CLI
Now let’s try it out.
Run:
node index.js count C:\Users\HarshGupta\Desktop\a.txt
Outputs:
There are 5 words in C:\Users\HarshGupta\Desktop\a.txt
We also get built-in CLI support for free:
node index.js --help
Usage: Counter [options] [command]
Counts the number of words in a file
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
count <file> Counts the number of words in a file
help [command] display help for command
More to it
You can add as many command you want, like this:
const fs = require("fs");
const {Command} = require("commander");
const program = new Command;
program
.name("Counter")
.description("Counts the number of words and lines in a file")
.version("0.0.0");
program.command("count")
.description("Counts the number of words in a file")
.argument('<file>', 'file to count')
.action((fileName) => {
fs.readFile(fileName, "utf-8", (err, data) => {
if(err){
console.log(err);
}
else{
let count = 0;
for(let i = 0; i < data.length; i++){
if(data[i] == " "){
count++;
}
}
console.log(`There are ${count + 1} words in ${fileName}`);
}
})
})
program.command("count_lines")
.description("Counts the number of lines in a file")
.argument('<file>', 'file to count')
.action((fileName) => {
fs.readFile(fileName, "utf-8", (err, data) => {
if(err){
console.log(err);
}
else{
let count = 0;
for(let i = 0; i < data.length; i++){
if(data[i] == "\n"){
count++;
}
}
console.log(`There are ${count} lines in ${fileName}`);
}
})
})
program.parse();
Conclusion
We just built a fully functional CLI word counter from scratch using Node.js. Starting with a simple script, we made it dynamic using process.argv
and then transformed it into a professional-grade CLI using commander.
This project might seem small, but the skills you’ve learned here are foundational for building real-world developer tools. Most CLI tools you use daily — like npm
, git
, or eslint
— are built on the same principles.
Subscribe to my newsletter
Read articles from Harsh Gupta directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Harsh Gupta
Harsh Gupta
I am a CSE undergrad learning DevOps and sharing what I learn.