Skip to content
Laviyx Learn

Try

JavaScript course menu

Node.js Basics: Running JavaScript on the Server

Get started with Node.js: what it is and what it is used for, the differences from browser JavaScript, process and command-line arguments, reading and writing files with node:fs/promises, paths, environment variables, and building a tiny HTTP server.

Advanced7 min readUpdated
On this page

Node.js runs JavaScript outside the browser, on servers and on your own computer. It uses the same V8 engine as Chrome, plus built-in modules for files, networking and the operating system. It is used for web servers and APIs, command-line tools, build tools, and real-time apps such as chat. Install it as described in Running JavaScript.

Browser JavaScript versus Node.js#

BrowserNode.js
LanguageSame JavaScriptSame JavaScript
Page accessdocument, window, the DOMNone
Files and OSNo direct access (for security)fs, path, os, child_process
Networkingfetch, WebSocketsfetch, plus servers with http
Global objectwindow (and globalThis)globalThis
Modules<script type="module">ES modules or CommonJS (Modules)

process: information about the running program#

JavaScript
console.log(typeof process.version);
console.log(process.version.startsWith("v"));
console.log(typeof process.cwd());
console.log(["win32", "darwin", "linux"].includes(process.platform));
Output
string
true
string
true

The exact values depend on your computer: process.version is the Node version (such as v24.x.x), process.platform is the operating system and process.cwd() is the current folder.

Command-line arguments#

process.argv holds the words typed after node:

greet.js (JavaScript)
const [, , name = "friend", times = "1"] = process.argv;
for (let i = 0; i < Number(times); i++) {
  console.log(`Hello, ${name}!`);
}
Terminal
node greet.js Asha 2
Output
Hello, Asha!
Hello, Asha!

The first two entries are the paths of node and the script, which is why the destructuring skips them.

Environment variables#

Configuration such as ports and API keys comes from environment variables, read through process.env:

JavaScript
const port = Number(process.env.PORT ?? 3000);
const apiKey = process.env.WEATHER_API_KEY;   // never hard-code secrets

Node.js 20.6 and later can load a .env file with node --env-file=.env app.js. Never commit .env files containing real secrets to Git.

Files#

The promise-based file API lives in node:fs/promises:

JavaScript
import { writeFile, readFile, appendFile, readdir, mkdir } from "node:fs/promises";
import path from "node:path";

await mkdir("notes", { recursive: true });
const file = path.join("notes", "todo.txt");

await writeFile(file, "Learn Node.js\n");
await appendFile(file, "Build an API\n");

const text = await readFile(file, "utf8");
console.log(text.trim().split("\n"));
console.log(await readdir("notes"));
Output
[ 'Learn Node.js', 'Build an API' ]
[ 'todo.txt' ]
  • Always pass an encoding ("utf8") to readFile to get a string; otherwise you get a raw Buffer.
  • File operations can fail (missing file, no permission), so wrap them in try...catch in real programs.

JSON files#

JavaScript
import { writeFile, readFile } from "node:fs/promises";

const settings = { theme: "dark", fontSize: 18 };
await writeFile("settings.json", JSON.stringify(settings, null, 2));

const loaded = JSON.parse(await readFile("settings.json", "utf8"));
console.log(loaded.theme, loaded.fontSize);
Output
dark 18

Paths#

Use node:path instead of joining paths with strings, so the code works on Windows (\) and Linux or macOS (/):

JavaScript
import path from "node:path";

console.log(path.basename("/data/reports/june.csv"));
console.log(path.extname("photo.final.jpeg"));
console.log(path.parse("/data/reports/june.csv").name);
Output
june.csv
.jpeg
june

In ES modules, import.meta.dirname gives the folder of the current file (Node.js 20.11 and later).

A tiny web server#

The built-in node:http module can serve web pages and APIs:

server.js (JavaScript)
import { createServer } from "node:http";

const courses = [
  { id: 1, name: "HTML" },
  { id: 2, name: "CSS" },
];

const server = createServer((req, res) => {
  if (req.method === "GET" && req.url === "/api/courses") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(courses));
    return;
  }
  res.writeHead(404, { "Content-Type": "text/plain" });
  res.end("Not found");
});

server.listen(3000, () => console.log("Listening on http://localhost:3000"));

Run node server.js and open http://localhost:3000/api/courses in your browser to see the JSON. Press Ctrl+C to stop the server.

Real projects usually use a framework such as Express, Fastify or Hono on top of this, which handles routing, request bodies and middleware. Full-stack frameworks such as Next.js combine a Node.js server with a React front end.

Asynchronous by design#

Node.js handles many connections at once on a single thread by never waiting idly: file and network operations are asynchronous, and the event loop runs callbacks as results arrive. Avoid the ...Sync versions of file functions (such as readFileSync) inside servers, because they block every other request while they run. They are fine in small scripts.

Practice#

Practice exercise

Write a script that creates scores.json containing [{ "name": "Asha", "score": 92 }, { "name": "Ravi", "score": 78 }], reads it back, and prints the average score and the name of the top scorer.

Show solution
JavaScript
import { writeFile, readFile } from "node:fs/promises";

const data = [
  { name: "Asha", score: 92 },
  { name: "Ravi", score: 78 },
];
await writeFile("scores.json", JSON.stringify(data));

const scores = JSON.parse(await readFile("scores.json", "utf8"));
const average = scores.reduce((sum, s) => sum + s.score, 0) / scores.length;
const top = scores.reduce((best, s) => (s.score > best.score ? s : best));

console.log("Average:", average);
console.log("Top scorer:", top.name);
Output
Average: 85
Top scorer: Asha

Key takeaway#

Finished this lesson?