A CLI-Powered Resume You Can Ship as an npm Package
Fresh off Ali Churcher’s CSS Grid resume concept, here’s a different angle: turn that idea into a reusable, interactive resume that lives entirely in the terminal. With Node.js and a couple of well-known libraries, you can scaffold a project that runs with a single npx command—no manual HTML edits each time you update your experience.

Project Setup
Start by creating a project folder and initializing it with npm or Yarn. The project name you choose becomes the package name when you publish to the npm registry.
mkdir your-project && cd "$_"
## npm
npm init
## Yarn
yarn init
Next, create two files: index.js will hold the application logic, and data.json will store your resume data. You can open both from the command line:
touch index.js && touch data.json
Data Model and Interactive Prompts
The core idea is to drive the resume data through an interactive command-line interface. You need two things: a data object and a prompt system—and Inquirer.js handles most of the heavy lifting for the latter.
Start with data.json. The example below defines the object keys and sub-sections you’ll use for each step of the interface. Feel free to adapt it to your own resume’s structure.
{
"Education": [
"Some info",
"Less important info",
"Etc, etc."
],
"Experience": [
"Some info",
"Less important info",
"Etc, etc."
],
"Contact": [
"A way to contact you"
]
}
To make the terminal output more readable, add chalk for color and text styling. Install both libraries:
yarn add inquirer chalk
Now open index.js and add the main application code:
#!/usr/bin/env node
"use strict";
const inquirer = require("inquirer");
const chalk = require("chalk");
const data = require("./data.json");
// add response color
const response = chalk.bold.blue;
const resumeOptions = {
type: "list",
name: "resumeOptions",
message: "What do you want to know",
choices: [...Object.keys(data), "Exit"]
};
function showResume() {
console.log("Hello, this is my resume");
handleResume();
}
function handleResume() {
inquirer.prompt(resumeOptions).then(answer => {
if (answer.resumeOptions == "Exit") return;
const options = data[`${answer.resumeOptions}`]
if (options) {
console.log(response(new inquirer.Separator()));
options.forEach(info => {
console.log(response("| => " + info));
});
console.log(response(new inquirer.Separator()));
}
inquirer
.prompt({
type: "list",
name: "exitBack",
message: "Go back or Exit?",
choices: ["Back", "Exit"]
}).then(choice => {
if (choice.exitBack == "Back") {
handleResume();
} else {
return;
}
});
}).catch(err => console.log('Ooops,', err))
}
showResume();
Breaking Down the Logic
The top of the file imports the required modules and sets up chalk’s color styles for a more polished output.
const inquirer = require("inquirer");
const chalk = require("chalk");
const data = require("./data.json");
// add response color
const response = chalk.bold.blue;
The resumeOptions array defines the main menu shown when the app runs. The choices field maps to the keys in your data object and adds an “Exit” option so you can stop the program cleanly.
const resumeOptions = {
type: "list",
name: "resumeOptions",
message: "What do you want to know",
choices: [...Object.keys(data), "Exit"]
};
The showResume() function serves as the entry point for the user—it prints a welcome message and kicks off the handleResume() flow.
function showResume() {
console.log("Hello, this is my resume");
handleResume();
}
handleResume() checks whether the user chose to exit; if not, it reads answer.resumeOptions and lists the matching sections from data.json—say, Education, Experience, and Contact. Inquirer’s new inquirer.Separator() adds visual breaks between those blocks.
To let users move back through the sections, a second inquirer.prompt offers only “Back” and “Exit.” Choosing “Back” recalls handleResume(), while “Exit” quits. A catch block rounds off the function for error handling.
Publishing to npm
You can test the app locally with:
node index.js
That works, but a real package should run from anywhere. Publishing makes that possible:
- Create an account at npmjs.com if you don’t already have one.
- Authenticate locally with
npm adduserand provide your credentials. - In
package.json, add thebinentry so the CLI command maps toindex.js:
"bin": {
"your-package-name": "./index.js"
}
README.md so the package page looks professional.npm publish.npm publish --access=public
To push updates after editing the resume data or logic, follow semantic versioning to bump the version:
npm version patch // 1.0.1
npm version minor // 1.1.0
npm version major // 2.0.0
Then republish:
npm publish
Running on Any Machine
Once the package is live, anyone—or you, from a fresh machine—can run it immediately with:
npx your-package-name
npx runs the package without a global install, and it ships with npm, so there’s no extra tooling setup needed.
The final project is minimal, but the same pattern—data in JSON, prompts via Inquirer, and a small entry point—scales naturally into more complex CLIs. The source code for this project is on GitHub for reference.



