Node.js is a JavaScript runtime built on Chrome's V8 engine. It lets you run JavaScript outside the browser, making it possible to build servers, command-line tools, and backend services with the same language you use on the frontend.
What Makes Node.js Different
In the browser, JavaScript has access to the DOM, window, and fetch. In Node.js, those do not exist. Instead, you get access to the file system, network, operating system, and other server-side APIs.
| Feature | Browser | Node.js |
|---|---|---|
| DOM access | Yes | No |
| File system | No | Yes (fs module) |
| HTTP server | No | Yes (http module) |
window object | Yes | No (global instead) |
| Module system | ES Modules | CommonJS + ES Modules |
| Package manager | N/A | npm, pnpm, yarn |
Installing Node.js
Download the LTS version from nodejs.org. Verify the installation:
node --version # e.g., v22.0.0
npm --version # e.g., 10.0.0Running JavaScript Files
Create a file called app.js:
const message = "Hello from Node.js!";
console.log(message);
console.log(`Running on ${process.platform}`);
console.log(`Node version: ${process.version}`);Run it:
node app.jsThe Module System
Node.js uses CommonJS modules by default. Each file is its own module.
Exporting from a Module
// math.js
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
module.exports = { add, multiply };Importing a Module
// app.js
const { add, multiply } = require("./math");
console.log(add(2, 3)); // 5
console.log(multiply(4, 5)); // 20
ES Modules in Node.js
You can use ES module syntax by either setting "type": "module" in package.json or using the .mjs extension:
// math.mjs
export function add(a, b) {
return a + b;
}
// app.mjs
import { add } from "./math.mjs";
console.log(add(2, 3));Built-in Modules
Node.js ships with many useful modules. No installation required.
fs — File System
const fs = require("fs");
// Read a file
const content = fs.readFileSync("data.txt", "utf-8");
console.log(content);
// Write a file
fs.writeFileSync("output.txt", "Hello, World!");
// Async version (preferred)
const fsPromises = require("fs/promises");
async function readConfig() {
const data = await fsPromises.readFile("config.json", "utf-8");
return JSON.parse(data);
}path — File Paths
const path = require("path");
const filePath = path.join(__dirname, "data", "users.json");
console.log(filePath);
// e.g., /home/user/project/data/users.json
console.log(path.extname("photo.jpg")); // ".jpg"
console.log(path.basename("/a/b/c.txt")); // "c.txt"
os — Operating System Info
const os = require("os");
console.log(os.platform()); // "linux", "darwin", "win32"
console.log(os.cpus().length); // number of CPU cores
console.log(os.totalmem()); // total memory in bytes
console.log(os.homedir()); // user's home directory
npm and Package Management
npm (Node Package Manager) manages third-party packages.
Initializing a Project
mkdir my-project && cd my-project
npm init -yThis creates a package.json file that tracks your project's dependencies and scripts.
Installing Packages
npm install express # production dependency
npm install -D nodemon # development dependencypackage.json Scripts
{
"name": "my-project",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"nodemon": "^3.0.0"
}
}Run scripts with:
npm run dev
npm startEnvironment Variables
Store configuration outside your code using environment variables.
// Access environment variables
const port = process.env.PORT || 3000;
const nodeEnv = process.env.NODE_ENV || "development";
console.log(`Server running on port ${port} in ${nodeEnv} mode`);Use a .env file with the dotenv package:
npm install dotenv# .env
PORT=4000
DATABASE_URL=mongodb://localhost:27017/myapp
SECRET_KEY=super-secret-valuerequire("dotenv").config();
console.log(process.env.DATABASE_URL);Never commit .env files to version control. Add .env to your .gitignore.
Creating a Simple HTTP Server
Node.js can create servers without any framework:
const http = require("http");
const server = http.createServer((req, res) => {
if (req.url === "/" && req.method === "GET") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ message: "Hello, World!" }));
} else if (req.url === "/health") {
res.writeHead(200);
res.end("OK");
} else {
res.writeHead(404);
res.end("Not Found");
}
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});This works but gets unwieldy fast. That is why frameworks like Express exist.
Practical Exercise
Build a file-based note-taking CLI tool:
const fs = require("fs/promises");
const path = require("path");
const NOTES_DIR = path.join(__dirname, "notes");
async function ensureDir() {
try {
await fs.mkdir(NOTES_DIR, { recursive: true });
} catch {}
}
async function addNote(title, content) {
await ensureDir();
const filename = `${title.toLowerCase().replace(/\s+/g, "-")}.txt`;
await fs.writeFile(path.join(NOTES_DIR, filename), content);
console.log(`Note saved: ${filename}`);
}
async function listNotes() {
await ensureDir();
const files = await fs.readdir(NOTES_DIR);
console.log("Your notes:");
files.forEach((f) => console.log(` - ${f}`));
}
const [, , command, ...args] = process.argv;
if (command === "add") {
addNote(args[0], args.slice(1).join(" "));
} else if (command === "list") {
listNotes();
} else {
console.log("Usage: node notes.js add <title> <content>");
console.log(" node notes.js list");
}
Key Takeaways
- Node.js lets you run JavaScript on the server with access to the file system, network, and OS.
- Use
require(CommonJS) orimport(ES Modules) to organize code into modules. - npm manages packages and project scripts through
package.json. - Environment variables keep secrets and configuration out of your source code.
- The built-in
httpmodule can create servers, but Express makes it much easier.