Episode 3 — NodeJS MongoDB Backend Architecture / 3.1 — Starting with NodeJS
3.1.c — Running Scripts with Node.js
In one sentence: Node.js scripts are plain JavaScript files executed with the
nodecommand, giving you access to powerful globals likeprocess,__dirname, and console methods that let you interact with the operating system, command line, and file system.
Navigation: ← 3.1 Overview · Next → 3.1.d NPM Basics
Table of Contents
- 1. Creating and Running Your First Script
- 2. Console Methods — Beyond console.log
- 3. The Process Object
- 4. Command-Line Arguments
- 5. Reading User Input with readline
- 6. __dirname and __filename
- 7. Global Objects — Node.js vs Browser
- 8. Modules Preview — Every File Is a Module
- 9. Namaste Duniya — Your First Real Program
- 10. Practical Script Examples
- Key Takeaways
- Explain-It Challenge
1. Creating and Running Your First Script
Step by step
# Step 1: Create a file
touch hello.js
// hello.js
console.log('Hello from Node.js!');
console.log('This is running OUTSIDE the browser.');
console.log('No DOM, no window — pure server-side JavaScript.');
# Step 2: Run it
node hello.js
# Hello from Node.js!
# This is running OUTSIDE the browser.
# No DOM, no window — pure server-side JavaScript.
Key points
- Any valid JavaScript file can be run with
node filename.js - The file extension
.jsis convention but Node.js does not require it - You can also use
.mjsfor ES Modules or.cjsfor explicit CommonJS - Node.js executes the file top to bottom, then exits (unless something keeps it alive, like a server or timer)
What keeps a Node.js process alive?
// This exits immediately after printing
console.log('Done!');
// Process exits — nothing else to do
// This keeps running — the server listens for connections
const http = require('http');
http.createServer((req, res) => res.end('Hi')).listen(3000);
// Process stays alive — event loop has work (listening socket)
// This keeps running — timer is active
setInterval(() => console.log('tick'), 1000);
// Process stays alive — event loop has a timer
2. Console Methods — Beyond console.log
Node.js provides a rich console object. Most developers only use console.log(), but there is much more.
console.log() — Standard output
// Basic output
console.log('Hello, world!');
// String interpolation
const name = 'Arjun';
console.log(`Hello, ${name}!`); // Template literal
console.log('Hello, %s!', name); // C-style format string
// Multiple arguments
console.log('Name:', name, 'Age:', 25); // Name: Arjun Age: 25
// Object output
const user = { name: 'Arjun', role: 'developer' };
console.log(user); // { name: 'Arjun', role: 'developer' }
console.log('User:', user);
console.error() and console.warn() — stderr
// These write to STDERR (not STDOUT) — important for piping/logging
console.error('ERROR: Database connection failed');
console.warn('WARNING: Deprecated function used');
// In the terminal they look the same, but you can redirect them separately:
// node app.js > output.log 2> errors.log
// STDOUT (console.log) → output.log
// STDERR (console.error, console.warn) → errors.log
console.table() — Tabular display
const users = [
{ name: 'Arjun', age: 25, city: 'Mumbai' },
{ name: 'Priya', age: 28, city: 'Delhi' },
{ name: 'Rahul', age: 22, city: 'Bangalore' },
];
console.table(users);
// ┌─────────┬──────────┬─────┬─────────────┐
// │ (index) │ name │ age │ city │
// ├─────────┼──────────┼─────┼─────────────┤
// │ 0 │ 'Arjun' │ 25 │ 'Mumbai' │
// │ 1 │ 'Priya' │ 28 │ 'Delhi' │
// │ 2 │ 'Rahul' │ 22 │ 'Bangalore' │
// └─────────┴──────────┴─────┴─────────────┘
// Select specific columns
console.table(users, ['name', 'city']);
console.time() and console.timeEnd() — Performance measurement
console.time('array-creation');
const arr = [];
for (let i = 0; i < 1000000; i++) {
arr.push(i * 2);
}
console.timeEnd('array-creation');
// array-creation: 42.567ms
// You can have multiple timers running simultaneously
console.time('fetch-users');
console.time('fetch-posts');
// ... do async work ...
console.timeEnd('fetch-users'); // fetch-users: 120.4ms
console.timeEnd('fetch-posts'); // fetch-posts: 85.2ms
console.count() — Invocation counter
function processItem(type) {
console.count(type);
}
processItem('fruit'); // fruit: 1
processItem('vegetable');// vegetable: 1
processItem('fruit'); // fruit: 2
processItem('fruit'); // fruit: 3
processItem('vegetable');// vegetable: 2
console.countReset('fruit');
processItem('fruit'); // fruit: 1 (reset!)
console.dir() — Deep object inspection
const nested = {
level1: {
level2: {
level3: {
level4: { deep: 'value' }
}
}
}
};
// console.log truncates deep objects
console.log(nested);
// { level1: { level2: { level3: [Object] } } }
// console.dir with depth control
console.dir(nested, { depth: null }); // Shows ALL levels
console.dir(nested, { depth: 2 }); // Shows 2 levels deep
console.dir(nested, { colors: true }); // Syntax highlighting
console.group() — Grouped output
console.group('User Details');
console.log('Name: Arjun');
console.log('Age: 25');
console.group('Address');
console.log('City: Mumbai');
console.log('State: Maharashtra');
console.groupEnd();
console.groupEnd();
// Output:
// User Details
// Name: Arjun
// Age: 25
// Address
// City: Mumbai
// State: Maharashtra
console.clear() — Clear the terminal
console.clear(); // Clears the terminal screen
All console methods summary
| Method | Output Stream | Purpose |
|---|---|---|
console.log() | stdout | General output |
console.error() | stderr | Error messages |
console.warn() | stderr | Warning messages |
console.info() | stdout | Informational (same as log) |
console.table() | stdout | Tabular data display |
console.time() / timeEnd() | stdout | Performance timing |
console.count() / countReset() | stdout | Call counting |
console.dir() | stdout | Deep object inspection |
console.group() / groupEnd() | stdout | Grouped/nested output |
console.trace() | stderr | Print stack trace |
console.assert() | stderr | Log only if assertion fails |
console.clear() | — | Clear terminal |
3. The Process Object
process is a global object in Node.js (no require needed) that provides information about and control over the current Node.js process.
process.argv — Command-line arguments
// args.js
console.log(process.argv);
node args.js hello world 42
# [
# '/Users/yourname/.nvm/versions/node/v20.11.0/bin/node', ← [0] path to node
# '/Users/yourname/project/args.js', ← [1] path to script
# 'hello', ← [2] first argument
# 'world', ← [3] second argument
# '42' ← [4] third argument
# ]
process.env — Environment variables
// env.js
console.log('NODE_ENV:', process.env.NODE_ENV);
console.log('HOME:', process.env.HOME);
console.log('PATH:', process.env.PATH);
// Custom environment variable
console.log('API_KEY:', process.env.API_KEY || 'not set');
# Set an environment variable when running
NODE_ENV=production API_KEY=secret123 node env.js
# NODE_ENV: production
# HOME: /Users/yourname
# PATH: /usr/local/bin:/usr/bin:...
# API_KEY: secret123
process.exit() — Exit the process
// exit-codes.js
const config = process.env.DATABASE_URL;
if (!config) {
console.error('ERROR: DATABASE_URL is required');
process.exit(1); // Exit with error code 1 (non-zero = error)
}
// ... rest of app ...
console.log('App started successfully');
process.exit(0); // Exit with code 0 (success) — rarely needed explicitly
Exit code conventions:
0 → Success (everything is fine)
1 → General error
2 → Misuse of command
Any non-zero → Something went wrong
process.cwd() — Current working directory
console.log('Current directory:', process.cwd());
// /Users/yourname/my-project
// Note: process.cwd() is WHERE you ran the command
// __dirname is WHERE the file lives (they can be different!)
process.pid and process.uptime()
console.log('Process ID:', process.pid); // 12345
console.log('Uptime:', process.uptime(), 'seconds'); // 0.045
console.log('Memory:', process.memoryUsage());
// {
// rss: 30932992, ← Resident Set Size (total memory)
// heapTotal: 6537216, ← V8 heap allocated
// heapUsed: 4275832, ← V8 heap actually used
// external: 810632, ← C++ objects bound to JS
// arrayBuffers: 10507 ← ArrayBuffers and SharedArrayBuffers
// }
process.nextTick() — Microtask scheduling
console.log('Start');
process.nextTick(() => {
console.log('Next tick callback'); // Runs before any I/O or timers
});
setTimeout(() => {
console.log('setTimeout callback'); // Runs in timers phase
}, 0);
console.log('End');
// Output:
// Start
// End
// Next tick callback ← nextTick fires before setTimeout
// setTimeout callback
process events
// Handle uncaught exceptions (last resort — log and exit gracefully)
process.on('uncaughtException', (err) => {
console.error('Uncaught Exception:', err.message);
process.exit(1);
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
// Handle graceful shutdown (Ctrl+C)
process.on('SIGINT', () => {
console.log('\nGracefully shutting down...');
// Close database connections, finish pending requests, etc.
process.exit(0);
});
// Runs when the process is about to exit
process.on('exit', (code) => {
console.log('Process exiting with code:', code);
// Only synchronous code works here — no async!
});
4. Command-Line Arguments
Basic parsing
// greet.js — A simple CLI tool
const args = process.argv.slice(2); // Remove node path and script path
const name = args[0] || 'World';
const greeting = args[1] || 'Hello';
console.log(`${greeting}, ${name}!`);
node greet.js Arjun Namaste
# Namaste, Arjun!
node greet.js
# Hello, World!
Parsing flags manually
// flags.js — Parse --key=value style flags
const args = process.argv.slice(2);
const flags = {};
args.forEach(arg => {
if (arg.startsWith('--')) {
const [key, value] = arg.slice(2).split('=');
flags[key] = value || true;
}
});
console.log('Flags:', flags);
node flags.js --name=Arjun --verbose --port=3000
# Flags: { name: 'Arjun', verbose: true, port: '3000' }
Built-in parseArgs (Node 18.3+)
// modern-args.js — Using Node.js built-in argument parser
const { parseArgs } = require('node:util');
const { values, positionals } = parseArgs({
options: {
name: { type: 'string', short: 'n' },
port: { type: 'string', short: 'p', default: '3000' },
verbose: { type: 'boolean', short: 'v', default: false },
},
allowPositionals: true,
});
console.log('Values:', values);
console.log('Positionals:', positionals);
node modern-args.js -n Arjun -p 8080 -v file1.txt file2.txt
# Values: { name: 'Arjun', port: '8080', verbose: true }
# Positionals: [ 'file1.txt', 'file2.txt' ]
5. Reading User Input with readline
Basic prompt
// ask.js — Read user input from the terminal
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('What is your name? ', (name) => {
rl.question('What is your age? ', (age) => {
console.log(`\nHello, ${name}! You are ${age} years old.`);
rl.close();
});
});
node ask.js
# What is your name? Arjun
# What is your age? 25
#
# Hello, Arjun! You are 25 years old.
Promise-based readline (Node 17+)
// ask-modern.js — Using promises (cleaner, no callback nesting)
const readline = require('readline/promises');
const { stdin: input, stdout: output } = require('process');
async function main() {
const rl = readline.createInterface({ input, output });
const name = await rl.question('What is your name? ');
const city = await rl.question('Where are you from? ');
const lang = await rl.question('Favorite language? ');
console.log(`\n${name} from ${city} loves ${lang}!`);
rl.close();
}
main();
Building a simple quiz
// quiz.js
const readline = require('readline/promises');
const { stdin: input, stdout: output } = require('process');
const questions = [
{ q: 'What does "npm" stand for?', a: 'node package manager' },
{ q: 'Who created Node.js?', a: 'ryan dahl' },
{ q: 'What engine does Node.js use?', a: 'v8' },
];
async function quiz() {
const rl = readline.createInterface({ input, output });
let score = 0;
for (const { q, a } of questions) {
const answer = await rl.question(`\n${q}\n> `);
if (answer.toLowerCase().trim() === a) {
console.log('Correct!');
score++;
} else {
console.log(`Wrong! The answer was: ${a}`);
}
}
console.log(`\nYour score: ${score}/${questions.length}`);
rl.close();
}
quiz();
6. __dirname and __filename
These are module-level variables available in every CommonJS file (not true globals).
// paths.js
console.log('__filename:', __filename);
// /Users/yourname/project/src/paths.js ← Full absolute path to THIS file
console.log('__dirname:', __dirname);
// /Users/yourname/project/src ← Directory containing THIS file
__dirname vs process.cwd()
// File is at: /Users/yourname/project/src/utils/helper.js
console.log('__dirname:', __dirname);
// /Users/yourname/project/src/utils ← Where the FILE is
console.log('process.cwd():', process.cwd());
// Depends on WHERE you ran the command:
// If you ran: cd /Users/yourname/project && node src/utils/helper.js
// → /Users/yourname/project
// If you ran: cd / && node /Users/yourname/project/src/utils/helper.js
// → /
Building file paths with __dirname
const path = require('path');
// Always use path.join with __dirname for reliable file paths
const configPath = path.join(__dirname, '..', 'config', 'database.json');
console.log(configPath);
// /Users/yourname/project/src/config/database.json
// Reading a file relative to the current script
const fs = require('fs');
const data = fs.readFileSync(path.join(__dirname, 'data.json'), 'utf8');
ES Modules equivalent
In ES Modules (.mjs or "type": "module"), __dirname and __filename are not available. Use this instead:
// helper.mjs (ES Module)
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__dirname);
console.log(__filename);
7. Global Objects — Node.js vs Browser
Browser global: window
// In the browser:
console.log(window); // The Window object
console.log(window.document); // The DOM
console.log(window.location); // Current URL
window.alert('Hello!'); // Show dialog
Node.js global: global
// In Node.js:
console.log(global); // The global object
// global.document → undefined (no DOM!)
// global.alert → undefined (no UI!)
// Things on global:
console.log(global.console); // console object
console.log(global.setTimeout); // setTimeout function
console.log(global.process); // process object
console.log(global.Buffer); // Buffer class
globalThis — The universal answer
// Works in BOTH browser and Node.js (ES2020)
console.log(globalThis);
// In browser: Window object
// In Node.js: global object
Comparison table
| Global | Browser | Node.js |
|---|---|---|
| Global object | window | global |
| Universal global | globalThis | globalThis |
| DOM | document, window.document | Not available |
| Location | window.location | Not available |
| Timers | setTimeout, setInterval | Same + setImmediate |
| Console | console | console (to stdout/stderr) |
| Fetch | fetch() (built-in) | fetch() (Node 18+ built-in) |
| URL | URL, URLSearchParams | Same (built-in) |
| Process | Not available | process |
| Buffer | Not available | Buffer |
| require | Not available (use import) | Available (CommonJS) |
Do NOT pollute the global scope
// BAD — attaching things to global
global.myConfig = { port: 3000 };
// Accessible anywhere, but untraceable and dangerous
// GOOD — use modules
// config.js
module.exports = { port: 3000 };
// app.js
const config = require('./config');
console.log(config.port); // 3000
8. Modules Preview — Every File Is a Module
In Node.js, every .js file is automatically a module. Variables and functions defined in one file are private to that file unless explicitly exported.
// --- math.js ---
const PI = 3.14159;
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
// Export what you want to share
module.exports = { add, multiply, PI };
// 'multiply' is not exported — it's private to this file
// --- app.js ---
const math = require('./math'); // Import the module
console.log(math.add(2, 3)); // 5
console.log(math.PI); // 3.14159
Why modules matter
Without modules: With modules:
┌─────────────────────┐ ┌─────────────────────┐
│ Everything in one │ │ auth.js — login logic│
│ giant file │ │ db.js — database │
│ (1000+ lines) │ │ api.js — routes │
│ Variables collide │ │ utils.js — helpers │
│ Hard to test │ │ Each file is isolated│
│ Hard to maintain │ │ Easy to test & reuse │
└─────────────────────┘ └─────────────────────┘
We will dive deep into CommonJS and ES Modules in the npm and package.json sections. For now, just know: every file is a module, and
require()is how you use other modules.
9. Namaste Duniya — Your First Real Program
Let us put everything together into a meaningful first program.
// namaste-duniya.js — Your first complete Node.js program
// ===== 1. Greeting =====
const greeting = 'Namaste Duniya!';
console.log('='.repeat(50));
console.log(` ${greeting}`);
console.log(` Welcome to Node.js ${process.version}`);
console.log('='.repeat(50));
// ===== 2. System Information =====
const os = require('os');
console.log('\n--- System Info ---');
console.table({
'Platform': os.platform(),
'Architecture': os.arch(),
'Hostname': os.hostname(),
'CPUs': os.cpus().length + ' cores',
'Total Memory': (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB',
'Free Memory': (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB',
'Uptime': (os.uptime() / 3600).toFixed(1) + ' hours',
});
// ===== 3. Process Information =====
console.log('\n--- Process Info ---');
console.log('PID:', process.pid);
console.log('Node version:', process.version);
console.log('Current directory:', process.cwd());
console.log('Script location:', __dirname);
console.log('Script file:', __filename);
// ===== 4. Environment Check =====
console.log('\n--- Environment ---');
const env = process.env.NODE_ENV || 'development';
console.log(`NODE_ENV: ${env}`);
console.log(`Home directory: ${process.env.HOME || process.env.USERPROFILE}`);
// ===== 5. Command-Line Arguments =====
const args = process.argv.slice(2);
if (args.length > 0) {
console.log(`\n--- Your Arguments ---`);
args.forEach((arg, i) => console.log(` [${i}] ${arg}`));
} else {
console.log('\nTip: Try running with arguments:');
console.log(' node namaste-duniya.js hello world 42');
}
// ===== 6. Performance =====
console.time('\nArray benchmark');
const bigArray = Array.from({ length: 1_000_000 }, (_, i) => i * 2);
const sum = bigArray.reduce((a, b) => a + b, 0);
console.timeEnd('\nArray benchmark');
console.log(`Sum of 1M elements: ${sum.toLocaleString()}`);
console.log('\n' + '='.repeat(50));
console.log(' Program complete. Namaste!');
console.log('='.repeat(50));
# Run it
node namaste-duniya.js
# ==================================================
# Namaste Duniya!
# Welcome to Node.js v20.11.0
# ==================================================
#
# --- System Info ---
# ┌─────────────────┬───────────────────────┐
# │ (index) │ Values │
# ├─────────────────┼───────────────────────┤
# │ 'Platform' │ 'darwin' │
# │ 'Architecture' │ 'arm64' │
# ...
# Run with arguments
node namaste-duniya.js Arjun Developer Mumbai
10. Practical Script Examples
Example 1: File counter
// count-files.js — Count files in a directory
const fs = require('fs');
const path = require('path');
const targetDir = process.argv[2] || '.';
const items = fs.readdirSync(targetDir);
const files = items.filter(item => {
const fullPath = path.join(targetDir, item);
return fs.statSync(fullPath).isFile();
});
const dirs = items.filter(item => {
const fullPath = path.join(targetDir, item);
return fs.statSync(fullPath).isDirectory();
});
console.log(`Directory: ${path.resolve(targetDir)}`);
console.log(`Files: ${files.length}`);
console.log(`Subdirectories: ${dirs.length}`);
console.log(`Total items: ${items.length}`);
Example 2: Simple timer
// timer.js — Countdown timer
const seconds = parseInt(process.argv[2]) || 10;
let remaining = seconds;
console.log(`Timer started: ${seconds} seconds`);
const interval = setInterval(() => {
remaining--;
process.stdout.write(`\r ${remaining} seconds remaining...`);
if (remaining <= 0) {
clearInterval(interval);
console.log('\n Time is up!');
}
}, 1000);
node timer.js 5
# Timer started: 5 seconds
# 3 seconds remaining... (updates in place)
# Time is up!
Example 3: JSON pretty printer
// pretty-json.js — Read and pretty-print a JSON file
const fs = require('fs');
const path = require('path');
const filePath = process.argv[2];
if (!filePath) {
console.error('Usage: node pretty-json.js <file.json>');
process.exit(1);
}
try {
const raw = fs.readFileSync(path.resolve(filePath), 'utf8');
const parsed = JSON.parse(raw);
console.log(JSON.stringify(parsed, null, 2));
} catch (err) {
if (err.code === 'ENOENT') {
console.error(`File not found: ${filePath}`);
} else if (err instanceof SyntaxError) {
console.error(`Invalid JSON: ${err.message}`);
} else {
console.error(`Error: ${err.message}`);
}
process.exit(1);
}
Key Takeaways
- Run any
.jsfile withnode filename.js— the file executes top to bottom and exits unless kept alive by a server, timer, or listener. console.table()andconsole.time()are underused gems — use them for debugging data and profiling performance.process.argvgives you command-line arguments —slice(2)to skip the node and script paths.process.envaccesses environment variables — useNODE_ENV,PORT,DATABASE_URLfor configuration.process.exit(1)terminates with an error code — use it for validation failures in scripts and CLI tools.__dirnameis the directory of the current file;process.cwd()is where the command was run from — they are often different.globalis Node.js's equivalent of the browser'swindow— but useglobalThisfor cross-environment code.- Every file is a module — variables are private by default, use
module.exportsandrequire()to share code between files.
Explain-It Challenge
Can you write a Node.js script from memory that: (1) reads a name from command-line arguments, (2) prints the current time, platform, and Node version, and (3) exits with code 1 if no name is provided? Aim for 10 lines or fewer.
Navigation: ← 3.1 Overview · Next → 3.1.d NPM Basics