Node.js Command Line Tools: Create Your Own JSON Formatter
Overview: Command line tools are powerful, especially when they can automate tedious tasks like checking or formatting data files. In this blog post, we’ll create a custom JSON formatter CLI tool with Node.js that reads an input JSON file and outputs either pretty-printed (formatted) or minified JSON directly to the terminal. You’ll learn how to structure a Node.js CLI project, parse arguments, handle files, and add professional touches like error handling and performance considerations.
1. Setting Up the Project
Let’s begin by initializing a simple Node.js project. Create a folder called json-formatter-cli and set up package.json.
mkdir json-formatter-cli
cd json-formatter-cli
npm init -y
We’ll then create our main script file:
touch index.js
chmod +x index.js
The chmod command makes our Node script executable from the terminal. Add this line at the top of index.js to make it a CLI tool:
#!/usr/bin/env node
This shebang tells the shell to run the script using Node.js whenever it’s executed as a command. Now we can build a CLI that feels native.
2. Reading Input Files and Handling Errors
We’ll rely on Node’s built-in fs module to read files. Let’s parse command-line arguments using process.argv which gives access to arguments provided by the user.
#!/usr/bin/env node
const fs = require('fs');
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('Usage: jsonfmt <file> [--minify]');
process.exit(1);
}
const filePath = args[0];
const shouldMinify = args.includes('--minify');
try {
const data = fs.readFileSync(filePath, 'utf8');
const json = JSON.parse(data);
const output = shouldMinify ? JSON.stringify(json) : JSON.stringify(json, null, 2);
console.log(output);
} catch (err) {
console.error('Error:', err.message);
process.exit(1);
}
This minimal CLI reads a JSON file, parses it safely, and prints formatted or minified output. It exits gracefully with error messages if something goes wrong (like invalid paths or invalid JSON).
3. Improving Developer Experience with CLI Flags
Let’s make our tool more flexible by adding additional options like choosing indentation levels or reading from stdin. We’ll use a simple parsing approach to detect flags.
const indentFlag = args.find(arg => arg.startsWith('--indent='));
const indentLevel = indentFlag ? parseInt(indentFlag.split('=')[1]) : 2;
const output = shouldMinify ?
JSON.stringify(json) :
JSON.stringify(json, null, indentLevel);
console.log(output);
Now our tool can do things like:
node index.js data.json --indent=4
node index.js data.json --minify
This approach is lightweight. If you want to support more elaborate CLI parsing, consider libraries such as yargs, commander, or minimist, which make CLI argument handling cleaner and more intuitive.
4. Creating a Global Command
To run this tool globally (from anywhere in your terminal), we can modify package.json to define a bin entry:
{
"name": "jsonfmt",
"version": "1.0.0",
"bin": {
"jsonfmt": "./index.js"
},
"dependencies": {}
}
Then, run the following command in your project directory:
npm link
This registers your CLI as a global command called jsonfmt on your system. Now you can execute it like any other shell tool:
jsonfmt ./sample.json --indent=4
Node.js automatically finds your CLI binary, runs it, and prints the output JSON in the desired format. It’s simple yet powerful.
5. Tips and Performance Considerations
JSON parsing and formatting are CPU-intensive operations for large files. Here are some tips for optimizing performance:
- Use streams: When working with very large JSON files, use
fs.createReadStream()and a streaming parser (e.g.,JSONStream) instead of reading the entire file at once. - Handle invalid JSON gracefully: Always include
try { ... } catch { ... }blocks to prevent crashes. - Support piping: Allow the CLI to read from
stdin. For example:
if (filePath === '-') {
let input = '';
process.stdin.on('data', chunk => (input += chunk));
process.stdin.on('end', () => {
const json = JSON.parse(input);
console.log(JSON.stringify(json, null, indentLevel));
});
} else {
// regular file handling
}
This makes the tool usable in shell pipelines, such as:
cat data.json | jsonfmt -
It’s a practical, Unix-style design pattern that plays well with other tools.
6. Wrapping Up
In this tutorial, we built a fully functional Node.js command line JSON formatter. You’ve learned how to handle command-line arguments, read and write files, add flags, and even turn your script into a global CLI command. This approach can be extended for many other data processing tools, such as CSV parsers or YAML formatters — the design pattern remains the same. With a bit of refinement, this small Node.js utility can fit perfectly in your daily developer toolkit.
Useful links:

