Node.js provides powerful utilities to develop command-line applications. Popular tools like Express Generator and Nodemon are examples of command-line applications built with Node.js.
In this tutorial, we’ll learn how to use Node.js to create command-line utilities and build a sample internet speed test application using the speedtest.net API.
Getting Started with Command Line Applications
Command-line applications (CLIs) allow users to interact with programs through text commands in a terminal or console interface. Node.js makes it easy to create these applications with its built-in modules and npm ecosystem.
Basic Hello World Command Line App:
Let’s start by creating a simple application that greets users by name. First, we’ll write code to print “Hello World” to the console:
console.log("Hello World");
Save this code in a file named cli.js and run it using:
node cli.js
You’ll see “Hello World” printed in your console. But what if we want to pass a name as an argument? Let’s modify our code to accept input from the command line:
#!/usr/bin/env node
console.log("Hello", process.argv[2]);
The first line #!/usr/bin/env node is a shebang that tells the system this script should be executed with Node.js. The process.argv array contains command-line arguments, with the third element (index 2) being the first user-provided argument.
Now when you run:
node cli.js Shahid
It will output: Hello Shahid
Making Script Globally Accessible:
To make your script accessible as a command from anywhere in your system, you need to create a package.json file:
{
"name": "HelloWorld",
"version": "1.0.0",
"description": "A simple greeting CLI",
"author": "",
"license": "ISC",
"bin": {
"sayHello": "cli.js"
},
"dependencies": {}
}
The bin field maps command names to the JavaScript files that should be executed when those commands are run. In this case, when users run sayHello, the system will execute cli.js.
Install your package globally:
npm install -g
Now you can run your command from anywhere:
sayHello Shahid
Building Speedtest CLI Application
Now let’s create a more useful application: a command-line tool to test internet speed using the speedtest.net API.
Setting Up the Project:
First, create a new directory for your project and initialize it:
mkdir speedtest-cli
cd speedtest-cli
npm init
Install the required dependencies:
npm install chalk progress speedtest-net --save
These packages will help us:
- speedtest-net: Wrapper for the speedtest.net API
- progress: Creates progress bars in the terminal
- chalk: Adds colors to terminal output
Create a package.json file:
{
"name": "speedtest-cli",
"version": "1.0.0",
"description": "Command line tool to test internet speed",
"main": "index.js",
"bin": {
"speedtest": "index.js"
},
"dependencies": {
"chalk": "^4.1.2",
"progress": "^2.0.3",
"speedtest-net": "^2.2.0"
},
"keywords": ["speedtest", "cli", "internet", "speed"],
"author": "",
"license": "ISC"
}
Creating Speedtest Application:
Now let’s write the main application code in index.js:
#!/usr/bin/env node
const speedTest = require('speedtest-net');
const ProgressBar = require('progress');
const chalk = require('chalk');
// Create a progress bar utility function
function createProgressBar(what) {
console.log(chalk.cyan(what));
return new ProgressBar('[:bar] :percent', {
complete: '=',
incomplete: ' ',
width: 40,
total: 100
});
}
async function runSpeedTest() {
try {
console.log(chalk.yellow('Starting speed test...'));
console.log(chalk.dim('This may take up to 30 seconds\n'));
// Create progress bars
const downloadBar = createProgressBar('Testing download speed');
const uploadBar = createProgressBar('Testing upload speed');
// Run the test
const result = await speedTest({
acceptLicense: true,
acceptGdpr: true,
progress: (progress) => {
if (progress.type === 'download') {
downloadBar.update(progress.percent / 100);
} else if (progress.type === 'upload') {
uploadBar.update(progress.percent / 100);
}
}
});
// Display results
console.log('\n' + chalk.green('✓') + ' Speed test completed!\n');
console.log(chalk.cyan('Server:') + ' ' + result.server.name + ' (' + result.server.location + ', ' + result.server.country + ')');
console.log(chalk.cyan('Ping:') + ' ' + result.ping.latency.toFixed(2) + chalk.dim(' ms'));
console.log(chalk.cyan('Jitter:') + ' ' + result.ping.jitter.toFixed(2) + chalk.dim(' ms'));
console.log(chalk.cyan('Download:') + ' ' + (result.download.bandwidth / 125000).toFixed(2) + chalk.dim(' Mbps'));
console.log(chalk.cyan('Upload:') + ' ' + (result.upload.bandwidth / 125000).toFixed(2) + chalk.dim(' Mbps'));
} catch (error) {
console.error(chalk.red('Error running speed test:'), error.message);
process.exit(1);
}
}
// Run the speed test
runSpeedTest();
This code:
- Imports the required modules
- Creates a function to display progress bars
- Defines an async function to run the speed test
- Displays the results in a user-friendly format with colors
Installing and Using Speedtest CLI:
Make the script executable:
chmod +x index.js
Install it globally:
npm install -g
Now you can run your speed test from anywhere:
speedtest
Advanced CLI Development Techniques
1. Using Commander.js for Complex CLIs:
For more complex command-line applications, consider using the Commander.js library, which simplifies argument parsing and help documentation:
#!/usr/bin/env node
const { program } = require('commander');
const speedTest = require('speedtest-net');
const chalk = require('chalk');
program
.version('1.0.0')
.option('-s, --server <id>', 'Use a specific server')
.option('-j, --json', 'Output results as JSON')
.option('-v, --verbose', 'Show detailed progress')
.parse(process.argv);
const options = program.opts();
async function runTest() {
// Implementation using options
}
runTest();
2. Adding Interactive Elements with Inquirer.js:
You can make your CLI more interactive using Inquirer.js:
const inquirer = require('inquirer');
async function promptUser() {
const answers = await inquirer.prompt([
{
type: 'list',
name: 'testType',
message: 'What would you like to test?',
choices: ['Download & Upload', 'Download only', 'Upload only', 'Ping only']
}
]);
// Run the appropriate test based on user selection
}
3. Displaying Results with Tables:
For structured data, you can use the cli-table3 package:
const Table = require('cli-table3');
function displayResults(results) {
const table = new Table({
head: ['Metric', 'Value', 'Unit'],
colWidths: [20, 10, 10]
});
table.push(
['Ping', results.ping.toFixed(2), 'ms'],
['Download', results.download.toFixed(2), 'Mbps'],
['Upload', results.upload.toFixed(2), 'Mbps']
);
console.log(table.toString());
}
Conclusion
We’ve learned how to develop command-line applications using Node.js, from basic argument handling to creating a full-featured internet speed test tool. Command-line utilities are incredibly useful for automation, development workflows, and system administration tasks.
The techniques covered in this tutorial can be applied to create various types of CLI applications, from simple scripts to complex tools with interactive features and rich output formatting.
For further exploration, consider checking out these libraries:
- Commander.js – A complete solution for Node.js command-line interfaces
- Inquirer.js – For creating interactive command prompts
- Chalk – For terminal string styling
- Ora – Elegant terminal spinners
- Boxen – Create boxes in the terminal
With these tools and techniques, you can create professional-grade command-line applications that enhance your productivity and simplify complex tasks.