Lessons available in both languages
MERN Stack · Interview Prep

Node.js interview questions & answers

181+ real Node.js interview questions with model answers, plus free lessons to learn the concepts. Prepare in English & Hinglish, then practise with an AI mock interview.

20 topics · 181+ questions

Hirenix kaise padhata hai

Ek chapter. 90 minute.
Interview ke liye taiyaar.

Har concept ek real-world problem se — jaisa production code mein aata hai, waisa. Ratna nahi padta, samajh aa jaata hai. Har question ka model answer diya hai: interviewer ko exactly kya bolna hai, aur kyun. Phir usi chapter ka AI mock interview.

  • 📖Concept, 5 min meinJargon nahi — seedhi baat
  • 🛠️Real-world problemJaisa production code mein aata hai
  • 💬Model answerInterview mein kya bolna hai
  • 🧠FlashcardsRevision 10 min mein
  • 🤖AI mock interviewFollow-up bhi poochta hai
  • 📊Weak topicsKahan phans rahe ho, pata chale
Ye chapter shuru karo — free🌐 English🇮🇳 Hinglish
A student learning an interview concept on Hirenix at home
Video playlistsyllabus ke hisaab se18h+
Hirenix chapterinterview ke hisaab se90 min

Farq content ka nahi, filter ka hai — sirf wahi jo production mein actually use hota hai aur interview mein actually poocha jaata hai. Kitaabi topics jo industry mein kahin nahi chalte, wo yahan nahi milenge.

Lessons available in both languages

What you’ll learn

  • Node.js kya hai?
  • Node vs Browser
  • Modules (CommonJS vs ESM)Free account
  • npm & package.jsonFree account
  • Node event loop (libuv)Free account
  • Async patternsFree account
  • EventEmitterFree account
  • Streams & BuffersFree account
  • File system (fs)Free account
  • HTTP moduleFree account
  • process & environmentFree account
  • Error handling in NodeFree account
  • path & os utilitiesFree account
  • Cluster & worker threadsFree account
  • npm scripts & nodemonFree account
  • Debugging Node appsFree account
  • Interview recapFree account
  • Project 1: CLI tool banao
  • Project 2: Raw HTTP server (bina framework)Free account
  • Project 3: File-based Todo APIFree account

Node.js kya hai?

Ek restaurant socho jisme ek super-fast waiter hai. Har table par khaana pakne ka wait karne ke bajaye, waiter tumhara order leta hai, kitchen ko de deta hai, aur turant agle table par chala jaata hai. Jab dish ready hoti hai, kitchen ek bell bajati hai aur waiter use deliver kar deta hai. Ek hi waiter poore bhare hall ko serve karta hai — kai jagah ek saath hokar nahi, balki kabhi khaali khada wait na karke.

Node.js me, wo akela waiter hai ek JavaScript thread. Kitchen hai operating system, jo ek saath hazaaron network connections par nazar rakh sakta hai bina kisi ko unke upar khada kiye. Bell hai event loop: jab koi I/O job ready hoti hai, uska callback queue me lag jaata hai aur akela thread use utha leta hai. To Node tumhare JS ke liye single-threaded hai, par wait us thread ke bahar hota hai, is liye wo baaki requests serve karta rehta hai — yahi "non-blocking, event-driven" ka matlab hai.

💡 Runtime = wo environment jo tumhari JavaScript ko actually chalata hai — ye tumhe engine plus extra built-in tools (files, network) deta hai. Node ek runtime hai, na language na framework.

💡 V8 = Google ka engine (wahi jo Chrome ke andar hai) jo JavaScript ko compile aur execute karta hai. Node V8 ko embed karta hai taaki JS server par, kisi bhi browser ke bahar chal sake.

💡 libuv = wo C library jo Node ko uska event loop deti hai. Network I/O ke liye ye OS ka apna non-blocking notification system use karti hai (epoll Linux par, kqueue macOS par, IOCP Windows par) — koi extra thread lagta hi nahi. libuv ek chhota worker pool bhi rakhti hai (by default 4 threads) jo sirf fs, dns.lookup, zlib, aur CPU-heavy crypto ke liye use hota hai.

🌍 Real-world example: Ek API server ke paas 5,000 open connections hain, har ek ek database read ka wait kar raha hai. Ek traditional one-thread-per-request server ko 5,000 threads chahiye hote. Node saari 5,000 sockets kernel ke paas register kar deta hai aur event loop ke poll phase me usse poochta hai "inme se kaun ready hai?" — kernel sirf utni sockets bataata hai jinme data aa gaya hai, aur Node sirf unke callbacks chalata hai. Koi thread kisi socket par khada nahi rehta, is liye ek Node process hazaaron concurrent connections saste me handle karta hai — APIs, chat apps, aur real-time dashboards ke liye perfect.

Node kahan weak hai: agar tum ek heavy CPU task chalao — images resize karna, ek bada loop crunch karna, hashing — to akela JS thread busy ho jaata hai aur kisi aur ko jawab nahi de sakta. Kitchen madad nahi kar sakti kyunki ye kaam pure JS computation hai, I/O nahi. Yahi classic "don't block the event loop" gotcha hai; CPU-heavy kaam ke liye tum worker_threads ya koi doosra tool use karte ho.

Node MERN me kahan fit hota hai: MongoDB, Express, React, Node. React browser me frontend hai; Node (aksar Express ke saath) hai backend — ye tumhara server chalata hai, MongoDB se baat karta hai, aur React ko JSON bhejta hai. Node wo engine hai jis par tumhari poori server-side JavaScript chalti hai.

Kab Node sahi chunaav hai: I/O-bound kaam me — APIs, real-time apps (chat, notifications, sockets), API gateways, ya kuch bhi jo zyadatar database ya kisi doosri service ka intezaar karta ho. Aur tab bhi jab team pehle se JavaScript likhti ho, kyunki poore stack me ek zubaan sach me sangathan ki bachat hai, sirf naara nahi.

Kab galat chunaav hai: CPU-bound kaam me — image aur video processing, bade paimane ki data crunching, machine learning training. Aapki JavaScript ek thread pe chalti hai, isliye bhaari hisaab har doosre user ko rok deta hai. Ek hot spot ke liye worker_threads kaam aata hai; agar poori app hi CPU-bound hai to doosra runtime seedha behtar baithta hai, aur interview me yahi kehna majboot jawab hai, kamzor nahi.

Kab farak nahi padta: chhote internal tools aur scripts me. Wahi chuniye jo team jaanti ho.

Trade-off kya hai: event loop intezaar wale kaam ke liye behisaab concurrency deta hai aur hisaab wale kaam ke liye kuch nahi — ek hi khoobi, do taraf se dekhi hui. Aur ecosystem dono taraf kaatta hai: npm ka matlab hai ki aapko jo chahiye wo lagbhag pehle se maujood hai, aur ye bhi ki chhote project me sau se zyada transitive dependencies aa jaati hain jinhe aapne kabhi padha nahi aur jinpe apni production process ka bharosa rakh rahe hain.

Standard definition: Node.js is a JavaScript runtime built on Chrome's V8 engine that lets you run JavaScript outside the browser; it is single-threaded, non-blocking, and event-driven, using libuv's event loop to handle I/O asynchronously — network I/O is handled by the OS kernel's event notification (epoll/kqueue/IOCP), while libuv's small thread pool covers only fs, dns.lookup, zlib and heavy crypto — so it excels at I/O-heavy applications.

const fs = require('fs');

console.log('1: before read');

// Slow I/O is offloaded to libuv; the callback runs later
fs.readFile(__filename, () => {
  console.log('3: file is ready');
});

console.log('2: after read (did not wait!)');

Node vs Browser

Socho ek hi actor do alag theatres me perform kar raha hai. Actor (uski acting skill) same hai — par ek theatre me backstage kitchen hai, doosre me library. Actor kya reach kar sakta hai, ye building par depend karta hai, uski acting par nahi. JavaScript wahi actor hai. Browser aur Node.js wo do theatres hain: same language, par aas-paas alag props pade hain.

Node.js me tum bilkul wahi JavaScript language chalate ho bilkul usi V8 engine par jo Chrome use karta hai. Loops, arrays, promises, Array.map, async/await — sab identical. Jo badalta hai wo hai host environment: har side tumhe kaunse global objects aur built-in APIs deta hai.

  • Browser deta hai: window, document, poora DOM, localStorage, alert — web page ko draw aur interact karne ke liye cheezein. (Dhyan do: fetch is list me nahi hai — wo Node me bhi ek global hai, v21 se stable aur v18 se bina flag ke, is liye fetch wala code dono me chalta hai.)
  • Node deta hai: global, process, require, Buffer, __dirname, __filename, aur core modules jaise fs (files), http (servers), path — operating system, files aur network se baat karne ke liye cheezein. Node me DOM bilkul nahi hai — server par koi web page hota hi nahi.

💡 Host environment = wo program jo V8 ko embed karta hai aur plain JavaScript ke upar extra objects/APIs add karta hai (browser, ya Node).

💡 DOM = Document Object Model — web page ka tree (document.querySelector, elements, buttons). Ye sirf browser me exist karta hai.

🌍 Real-world example: Tum ek formatDate() helper likhte ho sirf plain JS use karke (Date, string methods). Ye browser aur Node dono me bina badle chalta hai — is liye validation/formatting logic share ho sakta hai. Par document.getElementById(...) call karne wala function Node me ReferenceError: document is not defined throw karta hai, aur fs.readFileSync(...) call karne wala function browser me throw karta hai (fs wahan hota hi nahi). Pure-language code freely travel karta hai; host-specific code nahi.

globalThis neutral bridge hai: ye browser me window ko point karta hai aur Node me global ko, is liye globalThis dono me kaam karta hai. Ise tab use karo jab tum global object ko touch karna chahte ho bina ye soche ki tum kaunse environment me ho.

💡 globalThis = "yahan ka global object" ke liye ek standard naam, chahe tum kisi bhi host me chal rahe ho.

Farak asal me kab kaatta hai: jab code ek taraf se doosri taraf copy karte hain. localStorage, document aur window Node me hote hi nahi, aur fs, process aur __dirname browser me nahi hote. "Local pe chal raha, browser me toot gaya" wale zyadatar bugs inhi aath naamon me se ek hote hain.

Kab logic Node me rakhiye, browser me nahi: koi bhi secret cheez (API keys, database credentials — browser bundle public hota hai, "chhupa hua" sirf tab tak jab tak koi devtools na khole), koi bhi cheez jispe bharosa karna ho (price ka hisaab, permission check — client kuch bhi bhej sakta hai), aur koi bhi bhaari kaam jo aap phone par nahi chahte.

Kab browser me hi rakhiye: jo sirf dikhane ke liye ho, aur jo turant mehsoos hona chahiye. Email field validate karne ke liye server tak jaana wo latency hai jo user bina wajah chukata hai.

Trade-off kya hai: "dono taraf ek hi zubaan" sach hai aur yahi wajah hai ki JavaScript ne poora stack jeeta — par isi se ye bhoolna aasaan ho jaata hai ki dono taraf ke bharose ke model ulte hain. Server code par bharosa hai aur wo niji hai; browser code public hai aur jo use chala raha hai wo use badal sakta hai. Validation function dono me baantna achhi aadat hai; use baant kar sirf browser me chalana security bug hai.

Standard definition (interview me bolo): Node.js and the browser both run JavaScript on the V8 engine, but they provide different host globals and APIs — the browser exposes window, document (the DOM), localStorage and alert, while Node exposes global, process, require, Buffer, __dirname and core modules like fs, http and path, with no DOM; some globals such as fetch now exist in both, and globalThis refers to the global object in either environment.

// Run this with: node file.js
console.log(typeof window);        // browser-only global
console.log(typeof process);       // Node-only global
console.log(process.version);      // Node-only API
console.log(typeof globalThis);    // works in BOTH

Project 1: CLI tool banao

Kya bana rahe hain: Ek chhota task CLI — ek command-line tool jise terminal mein aise chalate ho: node cli.js add "buy milk", node cli.js list, node cli.js remove 2. Ye tumhare tasks ko disk pe ek plain JSON file mein save karta hai, to program band hone ke baad bhi tasks bache rehte hain. Zero external packages — sirf Node ke built-in process, fs, aur path. Ye har CLI ka sabse important loop sikhata hai: argv padho → decide karo kya karna hai → data file padho → usse badlo → data file wapas likho → result print karo → exit. Ye pakka aa gaya to samajh jaoge ki npm, git, aur har doosra command-line tool andar se kaise juda hai.

Concepts jo ye sikhata hai: process.argv (program ko kaise pata chalta hai user ne kya type kiya), subcommand parsing (add / list / remove), fs.promises se JSON file padhna & likhna, safe file path ke liye path.join, console.log se stdout pe print karna, aur exit codes (process.exitCode = 1 = fail, 0 = success).


Step 0 — Mental model (pehle ye padho, 30 second)

Ek CLI tool bas ek normal Node script hai. Naya idea sirf ek hai: user isse baat karta hai filename ke baad words type karke, aur wo words tumhare program ke andar ek array process.argv mein aa jaate hain. Tumhara poora kaam: us array ko dekho, samjho user kya chahta hai, wo karo, kuch print karke wapas do, aur exit ho jao. Na server, na browser — bas argv andar aata hai, text bahar jaata hai, aur disk pe ek file jo runs ke beech cheezein yaad rakhti hai.

💡 process.argv = un words ka array jo user ne command line pe type kiye. Node ise tumhare code chalne se pehle bhar deta hai.

Ye picture dimaag mein rakho. Ab banate hain.


Step 1 — Dekho user ne kya type kiya (process.argv)

// cli.js
console.log(process.argv);

node cli.js add "buy milk" chalao aur ye milega:

[
  '/usr/local/bin/node',   // [0] node binary
  '/home/you/cli.js',      // [1] is script ka path
  'add',                   // [2] pehla asli argument
  'buy milk'               // [3] doosra asli argument
]

Ho ye raha hai: Node har script ko ek global process object deta hai, aur process.argv command line pe jo kuch tha uska array hai. Wo baat jo har beginner ko fasati hai: pehle do slot hamesha node aur script ka path hote hain. Tumhare asli arguments index 2 se shuru hote hain. To hum unhe slice kar dete hain:

const args = process.argv.slice(2);   // ['add', 'buy milk']
const command = args[0];              // 'add'  → subcommand
const rest = args.slice(1);           // ['buy milk'] → uske baad ka sab

💡 slice(2) pehle do items (node + script path) hata deta hai, taaki args mein sirf wahi ho jo user ne type kiya.

Ab command batata hai kya karna hai aur rest us command ka data hai. Ye split har CLI ka dil hai.


Step 2 — Decide karo data kahaan rakhna hai (path.join)

Hamare tasks kahin save hone chahiye taaki agli baar bhi wahaan hon. Hum script ke bagal mein tasks.json naam ki file use karenge.

const path = require('path');
const DATA_FILE = path.join(__dirname, 'tasks.json');

Ho ye raha hai: __dirname ek Node built-in hai — wo folder jismein ye script hai. path.join folder + filename ko ek sahi path mein jod deta hai (/home/you/tasks.json), operating system ke hisaab se sahi slash use karke (/ Mac/Linux pe, \ Windows pe). Hum kabhi bhi string + se path haath se nahi banate, kyunki wo alag-alag platforms pe toot jaata hai.

💡 __dirname = current file ka absolute folder path. path.join kisi bhi OS ke liye path ke tukdon ko safely jodta hai.


Step 3 — JSON file padho (aur "file abhi hai hi nahi" handle karo)

const fs = require('fs').promises;

async function readTasks() {
  try {
    const raw = await fs.readFile(DATA_FILE, 'utf8');
    return JSON.parse(raw);
  } catch (err) {
    if (err.code === 'ENOENT') return [];   // file abhi nahi hai → khali se shuru
    throw err;                              // koi doosra error → aage jaane do
  }
}

Ho ye raha hai — trace karo:

  1. fs.readFile(DATA_FILE, 'utf8') file padhta hai. Kyunki humne fs.promises liya, ye ek promise deta hai, to hum await karte hain. 'utf8' matlab "mujhe string do, raw bytes nahi."
  2. File mein text hai jaise ["buy milk"]. JSON.parse us text ko ek asli JavaScript array mein badal deta hai.
  3. Gotcha: sabse pehli baar jab tool chalao, tasks.json abhi exist hi nahi karti, to readFile err.code === 'ENOENT' ("Error NO ENTry") ke saath error phenkta hai. Hum bilkul isi case ko catch karke khali array [] return karte hain — fresh start. Koi doosra error (maano corrupt permissions) hum re-throw karte hain, kyunki use chup-chaap nigalna asli bugs ko chhupa dega.

💡 ENOENT = "file ya folder nahi mila" ke liye Node/OS ka error code. err.code check karke sirf usi case ko saaf handle kar sakte ho.


Step 4 — JSON file wapas likho

async function writeTasks(tasks) {
  await fs.writeFile(DATA_FILE, JSON.stringify(tasks, null, 2), 'utf8');
}

Ho ye raha hai: JSON.stringify(tasks, null, 2) hamare array ko wapas text mein badalta hai, aur 2 use 2-space indentation ke saath pretty-print karta hai taaki file insaan padh sake. fs.writeFile phir poori file ko us text se overwrite kar deta hai. (writeFile file ko poori tarah replace karta hai — append nahi karta. Agar bina dobara likhe add karna ho to wo fs.appendFile hai, par chhoti task list ke liye poori file dobara likhna sabse simple aur safe hai.)

💡 JSON.stringify(x, null, 2) = ek JS value ko pretty JSON text mein badalo, 2 space se indent karke.


Step 5 — add command (ye sabse bada hai — end to end trace karo)

async function main() {
  const args = process.argv.slice(2);
  const command = args[0];

  if (command === 'add') {
    const text = args[1];
    if (!text) {
      console.error('Error: please provide a task, e.g. node cli.js add "buy milk"');
      process.exitCode = 1;
      return;
    }
    const tasks = await readTasks();
    tasks.push(text);
    await writeTasks(tasks);
    console.log(`Added: "${text}"  (you now have ${tasks.length} task(s))`);
  }
}

main();

Ab node cli.js add "buy milk" ka poora safar step-by-step trace karo — ye poora tool ek hi flow mein hai:

  1. Tum node cli.js add "buy milk" type karke Enter dabate ho.
  2. Node shuru hota hai, process.argv bharta hai, aur tumhari file upar se neeche chalata hai, jo main() call karta hai.
  3. args = process.argv.slice(2)['add', 'buy milk']. command hai 'add'.
  4. if (command === 'add') branch chalta hai. text = args[1]'buy milk'.
  5. Guard check: text maujood hai, to error branch skip. (Agar user text bhoolta, to hum stderr pe error print karte, process.exitCode = 1 set karte aur return karte — ek non-zero exit code jo shell ko batata hai "ye fail hua.")
  6. await readTasks()tasks.json kholta hai. Pehli baar? Usne ENOENT phenka, to humein wapas [] mila.
  7. tasks.push('buy milk') — array ab ['buy milk'] hai.
  8. await writeTasks(tasks)JSON.stringify use text banata hai aur fs.writeFile use disk pe save karta hai. Tumhara task ab permanent hai.
  9. console.log(...) confirmation ko stdout pe print karta hai — wo text jo tumhe terminal mein dikhta hai.
  10. main() khatam, kuch bacha nahi, to Node khud code 0 (success) ke saath exit ho jaata hai.

Key insight: program ne chaar cheezein order mein ki — argv parse → file read → array mutate → file write → print. Har subcommand isi exact sequence ka variation hai.


Step 6 — list aur remove commands

  else if (command === 'list') {
    const tasks = await readTasks();
    if (tasks.length === 0) {
      console.log('No tasks yet. Add one with: node cli.js add "..."');
    } else {
      tasks.forEach((t, i) => console.log(`${i + 1}. ${t}`));
    }
  }

  else if (command === 'remove') {
    const index = Number(args[1]) - 1;   // user 1-based type karta hai, arrays 0-based hote hain
    const tasks = await readTasks();
    if (Number.isNaN(index) || !tasks[index]) {
      console.error(`Error: no task at position ${args[1]}`);
      process.exitCode = 1;
      return;
    }
    const [removed] = tasks.splice(index, 1);
    await writeTasks(tasks);
    console.log(`Removed: "${removed}"`);
  }

  else {
    console.error(`Unknown command: ${command || '(none)'}`);
    console.error('Usage: add <text> | list | remove <number>');
    process.exitCode = 1;
  }

Ho ye raha hai:

  • list read-only hai: file padho, aur ya to "no tasks yet" bolo ya forEach se loop karke har task ko 1-based number (i + 1) ke saath print karo taaki insaan ko natural lage.
  • remove ek number leta hai. User 1-based positions mein sochta hai ("task 2 hatao"), par arrays 0-based hote hain, to hum Number(args[1]) - 1 karte hain. Hum validate karte hain: agar input number hi nahi (Number.isNaN) ya wahaan koi task nahi, to exit code 1 ke saath error dete hain. Warna splice(index, 1) us ek item ko kaat deta hai, hum save karke confirm karte hain.
  • else (default) branch node cli.js addd jaise typos pakadta hai. Ek usage hint print karke non-zero exit karna hi CLI ko polished banata hai — wahi cheez git karta hai jab tum command galat type karte ho.

💡 1-based vs 0-based: insaan 1 se ginte hain, arrays 0 se index karte hain. Off-by-one bugs bilkul yahin rehte hain — hamesha boundary pe convert karo.


Step 7 — Ise ek asli command jaisa banao (shebang + bin)

Abhi tum node cli.js add "..." type karte ho. Asli tools jaise npm mein tum bas npm ... likhte ho. Do chhote tukde ye karte hain:

1. Shebangcli.js ki sabse pehli line:

#!/usr/bin/env node

Ye line operating system ko batati hai "is file ko node se chalao." /usr/bin/env node matlab "user ke PATH pe node dhoondo aur use karo" — machines ke beech portable. (Mac/Linux pe tum chmod +x cli.js bhi karoge use executable mark karne ke liye.)

2. package.json mein bin field:

{
  "name": "task-cli",
  "version": "1.0.0",
  "bin": { "task": "cli.js" }
}

bin ek command name (task) ko tumhari file se map karta hai. npm link ke baad (ya jab user tumhara package install kare), npm — Node nahi — apni global bin directory mein task naam ka ek symlink (Windows pe .cmd shim) banata hai jo cli.js ki taraf point karta hai, aur wo directory tumhare PATH pe hoti hai. Ab task add "buy milk" kahin se bhi chalta hai — na node, na path. Bilkul isi tarah nodemon, create-react-app, aur eslint jaise tools terminal commands bante hain.

💡 shebang = #!... pehli line jo OS ko batati hai kaunsa interpreter file chalayega. bin field = ek command name ko script se map karta hai taaki wo asli terminal command ban jaaye.


🔎 Poora flow (wiring ka recap)

Ye raha finished tool, command-by-command:

  1. node cli.js add "buy milk"argv.slice(2) = ['add','buy milk']command='add'readTasks() (ENOENT → []) → push('buy milk')writeTasks ["buy milk"] save → prints Added: "buy milk" → exit 0.
  2. node cli.js listcommand='list'readTasks()['buy milk']forEach prints 1. buy milk → exit 0.
  3. node cli.js remove 1command='remove'index = 1 - 1 = 0readTasks()splice(0,1) 'buy milk' kaatta hai → writeTasks [] save → prints Removed: "buy milk" → exit 0.
  4. node cli.js oops → koi branch match nahi → else usage print → process.exitCode = 1 (fail).

Har command wahi beats follow karta hai: argv parse → JSON file read → array change → wapas write → print → sahi code ke saath exit.


✅ Jo tumne abhi seekha

  • process.argv — CLI user ke words kaise dekhta hai; asli arguments index 2 se shuru hote hain, isliye .slice(2).
  • Subcommand parsingargs[0] command hai, baaki uska data; ek if/else (ya switch) har action ko route karta hai.
  • fs.promises read/write — load karne ke liye await fs.readFile(path,'utf8') + JSON.parse, save karne ke liye JSON.stringify + fs.writeFile; pehli-baar wale ENOENT ko [] return karke handle karo.
  • path.join(__dirname, ...) — strings jodne ki jagah ek safe, cross-platform path banao.
  • stdout vs stderr & exit codes — results ke liye console.log, failures ke liye console.error + process.exitCode = 1 taaki scripts unhe detect kar saken. Print karne ke turant baad process.exit(1) mat karo — message katt sakta hai.
  • shebang + bin — do tukde jo node cli.js ko PATH pe ek asli task command mein badal dete hain.
  • Universal CLI loopargv → read → change → write → print → exit. Har command-line tool isi pe bana hai.
#!/usr/bin/env node
const fs = require('fs').promises;
const path = require('path');

const DATA_FILE = path.join(__dirname, 'tasks.json');

async function readTasks() {
  try {
    const raw = await fs.readFile(DATA_FILE, 'utf8');
    return JSON.parse(raw);
  } catch (err) {
    if (err.code === 'ENOENT') return [];
    throw err;
  }
}

async function writeTasks(tasks) {
  await fs.writeFile(DATA_FILE, JSON.stringify(tasks, null, 2), 'utf8');
}

async function main() {
  const args = process.argv.slice(2);
  const command = args[0];

  if (command === 'add') {
    const text = args[1];
    if (!text) {
      console.error('Error: please provide a task, e.g. node cli.js add "buy milk"');
      process.exitCode = 1;
      return;
    }
    const tasks = await readTasks();
    tasks.push(text);
    await writeTasks(tasks);
    console.log(`Added: "${text}"  (you now have ${tasks.length} task(s))`);
  } else if (command === 'list') {
    const tasks = await readTasks();
    if (tasks.length === 0) {
      console.log('No tasks yet. Add one with: node cli.js add "..."');
    } else {
      tasks.forEach((t, i) => console.log(`${i + 1}. ${t}`));
    }
  } else if (command === 'remove') {
    const index = Number(args[1]) - 1;
    const tasks = await readTasks();
    if (Number.isNaN(index) || !tasks[index]) {
      console.error(`Error: no task at position ${args[1]}`);
      process.exitCode = 1;
      return;
    }
    const [removed] = tasks.splice(index, 1);
    await writeTasks(tasks);
    console.log(`Removed: "${removed}"`);
  } else {
    console.error(`Unknown command: ${command || '(none)'}`);
    console.error('Usage: add <text> | list | remove <number>');
    process.exitCode = 1;
  }
}

main();

Node.jsinterview questions & answers

10 sample questions below — 181+ in the full bank inside.

Node me main console methods kaunse hain aur kab use karte ho?

console.log normal info print karta hai, console.error aur console.warn errors/warnings print karte hain (stderr par), console.table arrays/objects ko ek saaf grid me dikhata hai, aur console.time / console.timeEnd batate hain ki koi block kitna time leta hai. Sahi method use karne se logs meaningful aur grep karne layak rehte hain.

In simple terms: console methods ko alag-alag colour ke highlighter pen samjho — log plain notes ke liye, error red danger mark ke liye, table ek tidy chart ke liye. Sahi pen use karne se notebook scan karna easy ho jaata hai. Jaise console.time('db'); await getUser(); console.timeEnd('db') kuch aisa print karta hai 'db: 42.5ms'.

Node ka cluster module kya karta hai?

cluster module tumhare Node process ki multiple copies fork karta hai (aam taur pe har CPU core ke liye ek). Linux/macOS pe default scheduling policy SCHED_RR hai: primary process asli listening socket apne paas rakhta hai aur incoming connections ko workers me round-robin tareeke se baant deta hai. Windows pe (aur jab explicitly set karo) policy SCHED_NONE hoti hai aur OS kernel decide karta hai ki kis worker ko konsi connection milegi. Dono cases me tumhara app har core use karke zyada requests handle kar sakta hai.

In simple terms: Ise aise samjho jaise ek receptionist (primary process) front desk apne paas rakhta hai aur visitors ko baari-baari back-office workers ko bhejta hai — ye Linux/macOS ka default (SCHED_RR) hai. Jaise 4-core Linux server pe cluster 4 worker processes fork karta hai; primary har connection accept karke round-robin se ek worker ko de deta hai, to chaar requests sach me parallel handle ho sakti hain.

Node me worker_threads kis kaam ke liye use hote hain?

worker_threads tumhe ek hi Node process ke andar real parallel threads pe JavaScript chalane dete hain, mainly CPU-heavy kaam (jaise hashing, image processing, ya bade calculations) main thread ko block kiye bina karne ke liye. cluster ke ulat, threads ek hi process me rehte hain aur SharedArrayBuffer se memory share kar sakte hain.

In simple terms: Main thread ko ek receptionist samjho jise visitors ko greet karne ke liye free rehna zaroori hai; bhaari paperwork back-office worker ko de diya jaata hai taaki desk kabhi jam na ho. Jaise 10 lakh passwords main thread pe hash karo to har request freeze ho jayegi, par ise ek Worker ke andar karo to server responsive rehta hai.

Agar Node single-threaded hai, to wo pehle se hazaron I/O operations ek saath kaise handle kar leta hai?

Network I/O (sockets, HTTP requests, network ke through DB connections) kernel-level hota hai — OS event loop ko epoll/kqueue/IOCP ke zariye batata hai jab data ready ho, isliye ye kabhi background thread tak jaata hi nahi. Sirf kuch specific blocking calls — fs (file system), dns.lookup, zlib, aur heavy crypto — libuv apne chhote background thread pool (default size 4) ko offload karta hai. Dono cases me single JS thread bas request fire karta hai aur kaam hone pe callback le leta hai, isliye I/O pehle se hi concurrent hai bina tumhare kuch kiye.

In simple terms: Ek waiter (JS thread) socho jo bahut saare orders leta hai. Zyadatar orders (network requests) ke liye wo bas ghanti bajata hai aur kitchen (OS) use bata deti hai jab ready ho — extra staff ki zaroorat nahi. Kuch specific chores ke liye (file check karna, DNS resolve karna) wo peeche ke 4 helpers (libuv ka thread pool) ko de deta hai taaki wo atka na rahe. Jaise 1000 users HTTP/DB calls kar rahe hon to kernel seedha event loop ko notify karta hai; par 1000 files ek saath padhna libuv ke 4-thread pool pe queue hota hai.

async/await kya karta hai?

async/await Promises ke upar syntactic sugar hai jo tumhe asynchronous code aise likhne deta hai jo synchronous code jaisa padhta hai. Ek async function hamesha ek Promise return karta hai, aur await uske andar tab tak ruk jaata hai jab tak Promise settle na ho, aur tumhe resolved value seedhe de deta hai. Rejections handle karne ke liye await ko try/catch me wrap karte ho.

In simple terms: Ye aise hai jaise token lekar chale jaane ki jagah queue me khade rehna — tum wahin khade rehte ho (await) jab tak serve na ho, phir khana haath me lekar aage badhte ho. Top-to-bottom follow karna aasan. Example: async function go(){ try { const u = await fetchUser(); console.log(u); } catch(e){ console.error(e); } }.

Node.js me error-first callback convention kya hai?

Ye Node ka standard callback shape hai jisme pehla argument hamesha error hota hai (ya null agar koi error nahi) aur data uske baad aata hai: (err, data) => {}. Pehle err check karo; agar truthy hai toh failure handle karo, warna data use karo. fs.readFile jaise core APIs isi pattern ko follow karti hain.

In simple terms: Ise aise samjho jaise delivery wala jo hamesha 'buri khabar pehle' deta hai — 'package damaged hai kya?' pehle, phir box handover. Toh tum hamesha problem pehle deal karte ho, saaman baad me. Example: fs.readFile('a.txt', (err, data) => { if (err) return console.error(err); console.log(data.toString()); }).

Callback hell kya hai?

Callback hell tab hota hai jab tum bahut saare dependent async callbacks ko ek dusre ke andar nest kar dete ho, jisse code ka deep pyramid ban jata hai jo right taraf khiskta jaata hai aur padhna aur error-handle karna mushkil ho jaata hai. Ye isliye hota hai kyunki har step pichle ke callback ka wait karta hai. Promises aur async/await isi ko flat karne ke liye aaye.

In simple terms: Socho instructions ke andar instructions ke andar instructions — 'jab shop pahuncho, jab bread mile, jab fresh ho, tab kharido' — har ek aur andar. Wo right-drift karta 'pyramid of doom' hi callback hell hai. Example: readFile(a, () => { readFile(b, () => { readFile(c, () => { /* deeply nested */ }) }) }).

Node single-threaded hai, to ek Node process by default kitne CPU cores use karta hai?

By default ek Node process tumhara JavaScript ek hi thread pe chalata hai, isliye machine me chahe jitne cores hon, wo sirf ek CPU core use karta hai. Baaki cores use karne ke liye multiple processes (cluster) chalane padte hain ya worker threads banane padte hain.

In simple terms: Socho ek shop me 4 billing counters hain par cashier sirf 1 — 3 counters khaali pade rehte hain. Default Node aisa hi hai: 8-core server, par tumhara JS ek core pe chalta hai. Jaise 8-core machine pe plain Express app phir bhi ~1 core use karega; baaki 7 idle rehte hain jab tak cluster ya worker_threads use na karo.

JavaScript/Node me Promise kya hai?

Promise ek object hai jo kisi async operation ke eventual result ko represent karta hai. Iske teen states hote hain — pending, fulfilled, ya rejected — aur ye tumhe .then() (success ke liye) aur .catch() (failure ke liye) attach karne deta hai, callbacks nest karne ki jagah. Promises chainable hote hain, jo sequential async steps ko flat kar deta hai.

In simple terms: Promise ko restaurant token jaisa samjho jo order dene ke baad milta hai — abhi khana nahi hai (pending), par token promise karta hai ki aa raha hai; baad me wo tumhara meal ban jaata hai (fulfilled) ya 'sorry, out of stock' (rejected). Example: fetchUser().then(u => console.log(u)).catch(e => console.error(e)).

Node me console.log aur console.error me kya farq hai?

console.log standard output (stdout) par likhta hai jabki console.error standard error (stderr) par likhta hai. Dono terminal me dikhte hain, lekin errors ko stderr par rakhne se jab tum output ko files ya pipes me redirect karte ho to real logs aur errors alag ho jaate hain.

In simple terms: Socho tumhare program se do alag pipe nikal rahe hain — ek normal messages ke liye, ek complaints ke liye. console.log normal pipe use karta hai, console.error complaints pipe, isliye tum unhe alag collect kar sakte ho. Jaise node app.js > out.log 2> err.log logs ko out.log me aur errors ko err.log me bhejta hai.

171+ more Node.js questions inside

Create a free account to read the full question bank, learn every topic, and practise with an AI mock interview.

Unlock all questions — free

Ready to practise Node.js?

Unlock every topic free, then face an AI interviewer that asks follow-ups and grades your answers.

Node.js Interview Questions & Answers | Hirenix