Managing multiple projects on your machine can get messy—especially if you’re constantly jumping between NestJS, Angular, and other apps. Wouldn’t it be great to have a command-line tool that lists all your projects, lets you choose one, and runs your desired command with a single keystroke?
That’s exactly what I built: a custom App Launcher CLI using Node.js. In this tutorial, I’ll show you how to make one yourself.
✨ Features
📂 Automatically scans a folder for apps/projects.
📌 Sorts apps by last modified for quick access.
⚡ Run custom commands like npm run start:dev or ng serve --open.
🛠 Commands are fully configurable in .env.
🖥 Optional: Convert it into a desktop EXE app with pkg.
🛑 Prerequisites
Node.js installed
Basic knowledge of running CLI commands
📂 Project Setup
Create a new folder and install dependencies:
mkdir app-launcher
cd app-launcher
npm init -y
npm install inquirer dotenv
⚙️ Add a .env File
Define your base path for apps and the commands you want available:
APPS_BASE_PATH=D:/apps
COMMAND_1_NAME=NestJS (Start Dev)
COMMAND_1_CMD=npm run start:dev
COMMAND_2_NAME=Angular (Serve with Open)
COMMAND_2_CMD=ng serve --open
COMMAND_3_NAME=Open Shell
COMMAND_3_CMD=cmd
📝 The App Launcher Code
Here’s the main script app-launcher.js:
const cp = require("child_process");
const fs = require("fs");
const path = require("path");
const inquirer = require("inquirer");
require("dotenv").config();
const style = {
reset: "\x1b[0m",
bright: "\x1b[1m",
fgGreen: "\x1b[32m",
fgCyan: "\x1b[36m",
fgYellow: "\x1b[33m",
fgMagenta: "\x1b[35m"
};
const APP_NAME = "App Launcher";
const APP_VERSION = "1.0.0";
const APP_AUTHOR = "Nasouh Mrstani / Senior Web Developer";
const APP_EMAIL = "nasouhmra@gmail.com";
const baseDir = process.env.APPS_BASE_PATH || "D:/apps";
function boxText(text) {
const line = "─".repeat(text.length + 2);
return [
style.fgCyan + `┌${line}┐` + style.reset,
style.fgCyan + ` ${text} ` + style.reset,
style.fgCyan + `└${line}┘` + style.reset,
].join("\n");
}
function showWelcome() {
const line = style.fgGreen + "═".repeat(50) + style.reset;
console.log(line);
console.log(boxText(style.bright + APP_NAME + " " + APP_VERSION + style.reset));
console.log(style.fgMagenta + `Author: ${APP_AUTHOR}` + style.reset);
console.log(style.fgCyan + `Email: ${APP_EMAIL}` + style.reset);
console.log(style.fgGreen + `Apps path: ${baseDir}` + style.reset);
console.log(line + "\n");
}
const COMMANDS = [];
for (let i = 1; ; i++) {
const name = process.env[`COMMAND_${i}_NAME`];
const cmd = process.env[`COMMAND_${i}_CMD`];
if (!name || !cmd) break;
const parts = cmd.split(" ");
COMMANDS.push({ name, cmd: parts });
}
async function main() {
showWelcome();
const dirs = fs.readdirSync(baseDir, { withFileTypes: true })
.filter(d => d.isDirectory())
.map(d => {
const folderPath = path.join(baseDir, d.name);
const stats = fs.statSync(folderPath);
return { name: d.name, value: folderPath, mtime: stats.mtime };
});
if (dirs.length === 0) {
console.log(style.fgMagenta + "❌ No folders found in " + baseDir + style.reset);
return;
}
dirs.sort((a, b) => b.mtime - a.mtime);
const { projectPath } = await inquirer.prompt([
{
type: "list",
name: "projectPath",
message: style.fgGreen + "Select a folder" + style.reset,
pageSize: 15,
choices: dirs.map(d => ({
name: style.fgCyan + d.name + style.reset,
value: d.value
})),
}
]);
console.log(boxText(path.basename(projectPath)));
const { command } = await inquirer.prompt([
{
type: "list",
name: "command",
message: `Choose a command for "${path.basename(projectPath)}"`,
choices: COMMANDS.map(c => ({ name: c.name, value: c.cmd })),
},
]);
console.log(style.fgYellow + `Running: ${command.join(" ")} in ${projectPath}` + style.reset);
cp.spawn(command[0], command.slice(1), {
cwd: projectPath,
shell: true,
stdio: "inherit"
});
}
main().catch(err => console.error("Error:", err));
▶️ Run the Launcher
Simply run:
node app-launcher.js
🖥 Convert to Desktop App (Optional)
If you want a single .exe you can run from your desktop:
npm install -g pkg
pkg app-launcher.js --targets node18-win-x64 --output app-launcher.exe
Now you have a portable Windows executable 🎉.
📬 Wrapping Up
With just a bit of Node.js and some CLI magic, you now have your own App Launcher that makes managing projects faster and easier.
✅ Clean interface
✅ Customizable with .env
✅ Runs on Windows as EXE with pkg
Top comments (0)