Chapter 3 of 18 · Node.js for Beginners — Complete Free Tutorial

Running JavaScript in Node

With Node installed and the REPL explored, the Node.js for Beginners series moves to the real workflow: writing scripts in files and running them. This chapter covers how Node executes a file, how your program reads command-line arguments, which console tools exist beyond log, and how timers keep work moving without blocking.

Running a file

Node loads the file, resolves any imports, then runs top to bottom. The filename ends in .js by convention — Node reads the text regardless, but the extension keeps editors and tools happy.

// greet.js
const who = process.argv[2] ?? 'world';
console.log(`Hello, ${who}!`);
console.log('Done.');   // this line always runs
node greet.js Asha

Expected output:

Hello, Asha!
Done.

Execution is top to bottom and single-threaded: line two finishes before line three starts. Nothing runs "in the background" unless you hand work to a timer, a promise or the file system — more on that in chapter 6.

Command-line arguments: process.argv

Everything the user typed arrives in an array. The first two slots are always the interpreter and the script path; your arguments start at index 2.

// argv-demo.js
const [nodePath, scriptPath, ...args] = process.argv;
console.log('node :', nodePath);
console.log('script:', scriptPath);
console.log('args :', args);
console.log('count:', args.length);
node argv-demo.js build --watch src

Expected output:

node : /Users/asha/.nvm/versions/node/v24.6.0/bin/node
script: /Users/asha/projects/argv-demo.js
args : [ 'build', '--watch', 'src' ]
count: 3
  • Args arrive as strings — convert with Number() or parseInt() before arithmetic.
  • Flags are just strings too: detect --watch with args.includes('--watch').
  • For serious CLI parsing (options with values, subcommands) reach for a library later; the array is enough for scripts.

console is bigger than log

The console object is a debugging toolbox that works identically in Node and the browser.

console.log('plain message');
console.error('this goes to stderr');   // separate stream — see below
console.warn('careful');

const tasks = [
  { task: 'write', done: true },
  { task: 'review', done: false },
];
console.table(tasks);

console.time('loop');
for (let i = 0; i < 1e6; i++) {}
console.timeEnd('loop');

Expected output:

plain message
┌─────────┬────────┬──────┐
│ (index) │  task  │ done │
├─────────┼────────┼──────┤
│    0    │ 'write' │ true │
│    1    │ 'review' │ false │
└─────────┴────────┴──────┘
loop: 1.823ms

console.log writes to stdout and console.error to stderr. Keeping errors on their own stream lets shell pipelines treat normal output and diagnostics separately — a habit that pays off in chapter 18.

Timers: doing two things at once

Node provides the browser timers plus a few extras. A timer does not pause your program — it schedules a callback and lets execution continue.

console.log('start');

const timer = setTimeout(() => console.log('3: timer fired'), 500);
setImmediate(() => console.log('2: immediate callback'));
console.log('end');

Expected output: start, end, then (order of the last two can vary between runs) 2: immediate callback followed by 3: timer fired after roughly half a second.

clearTimeout(timer) cancels a pending timer. Because the event loop keeps running until its queues empty, a pending timer is one of the classic reasons a script "will not exit" — you will meet that again with servers that deliberately never exit.

Exit codes and finishing cleanly

Scripts end when the event loop has nothing left to do; the exit status defaults to 0 (success). Scripts that fail should say so:

if (!process.argv[2]) {
  console.error('Usage: node backup.js [folder]');
  process.exitCode = 1;      // set now, exit happens at the end
} else {
  console.log('backed up', process.argv[2]);
}

Expected output: Usage: node backup.js [folder] followed by a shell status of 1 (verify with echo $? in bash or echo $LASTEXITCODE in PowerShell). Prefer process.exitCode over process.exit(): the latter skips pending cleanup work.

Common mistakes

  • Reading argv[1] as user input — index 1 is your own script path; user arguments start at index 2.
  • Arithmetic on strings — argv[3] * 2 concatenates or yields NaN; convert types explicitly.
  • Ignoring stderr — logging errors with console.log mixes them into valid output and breaks pipelines.
  • Using process.exit() mid-work — pending writes and clean-up callbacks are abandoned; set exitCode instead.
  • Expecting timers to block — they schedule, they do not sleep; use synchronous waits only in throwaway REPL tests.

Practice checklist

  1. Write temperature.js that takes a Celsius value as an argument and prints Fahrenheit.
  2. Print process.argv with and without arguments and explain every index.
  3. Convert an existing debugging session to console.table and console.time.
  4. Build a script that fails with exitCode = 1 when an argument is missing, and check the status code in the shell.
  5. Schedule two timers with different delays and observe which callback fires first.

You can run single-file scripts — real projects soon need many files. Next: The Node Module System.

Quiz: Running JavaScript in Node

5 questions · 70% to pass

Frequently Asked Questions

Node.js is a runtime that executes JavaScript outside the browser. It combines Google's V8 engine with APIs for files, networks, processes and streams, plus a package ecosystem (npm). You use it to build servers, command-line tools, APIs and anything that needs JavaScript running on a machine rather than in a page.

JavaScript is the language; Node.js is one environment that runs it. In the browser the language comes with a DOM, events and window APIs — in Node those are replaced by the file system, network and process modules. Syntax, functions, arrays, promises and async/await are identical, so your JavaScript knowledge transfers directly.

Browser code is sandboxed: it cannot read your files or open arbitrary ports. Node code has full machine access, which is why it is used for servers and tools but also why you never run untrusted code in it. There is no document or window in Node — the equivalents are global, process and modules.

npm is JavaScript's package manager and public registry. package.json describes your project: name, entry point, dependencies with version ranges, and scripts such as npm run dev. Installing a package copies it into node_modules and records the exact intent in package-lock.json so every machine installs identical versions.

Express is a minimal web framework for Node: a few thousand lines that give you routing, middleware, request parsing and static files on top of the raw HTTP server. It is the most common starting point for REST APIs and the backbone of this tutorial's project chapters.

Both work. CommonJS (require/module.exports) is the classic Node format; ES modules (import/export) are the standard and activated in a package.json with "type": "module". Modern projects favour ESM for browser compatibility, but you will read both in existing code, so this course teaches each.

Middleware are functions that run between the incoming request and the final response, in order: body parsing, logging, authentication, rate limits, error handling. Each receives the request, response and next function and can respond itself or pass control along — Express's pipeline model in one sentence.

A JSON file is perfect for learning CRUD: no setup, readable data, easy to reset. The moment you need concurrent writes, querying or multiple users, move to a real database — MySQL/PostgreSQL for relational data or MongoDB for documents. The storage chapter isolates persistence behind one module so swapping it later is straightforward.

A REST API exposes resources over HTTP using verbs on URLs: GET /api/todos lists, POST creates, PUT or PATCH updates, DELETE removes, and everything answers with JSON plus correct status codes (200, 201, 400, 404, 500). It is stateless — each request carries its own authentication — which makes it easy to cache, scale and consume from any frontend.

Node apps are long-running processes, not static files: deploy them to a Node-friendly host (a VPS, Render, Railway or Fly.io), keep secrets in environment variables, terminate HTTPS at a reverse proxy or platform edge, and send logs somewhere durable. The final chapter covers the full checklist including health checks and graceful shutdown.