Toolmingo
Guides19 min read

Node.js Tutorial for Beginners (2025): Learn Node Step by Step

Complete Node.js tutorial for absolute beginners. Learn Node.js from scratch: modules, npm, Express, file system, REST APIs, async programming, and build real projects. Free guide with code examples.

Node.js lets you run JavaScript outside the browser — on servers, in the terminal, and anywhere you need backend code. If you already know some JavaScript, Node.js is your path to building web servers, APIs, and command-line tools. If you're brand new, this tutorial covers everything from installation to building real projects.

What you'll learn

Topic What you'll be able to do
Setup Install Node.js and run your first script
Modules Organize code with require and import
npm Install and manage packages
File system Read and write files
HTTP & Express Build web servers and REST APIs
Async programming Handle async code with callbacks, Promises, async/await
Real projects Build a CLI tool, REST API, and file processor

Why Node.js?

Use case Example
Web servers Express, Fastify, Hono
REST APIs JSON APIs for mobile/web apps
Real-time apps Chat, live notifications (Socket.io)
CLI tools Scripts, automation, build tools
Microservices Lightweight services at scale
Serverless AWS Lambda, Vercel functions
Job market ~300k+ Node.js jobs worldwide

Node.js vs other backend languages

Node.js Python Go Java
Language JavaScript Python Go Java
Speed Fast (V8 engine) Moderate Very fast Fast
Async model Event loop, non-blocking Threads / asyncio Goroutines Threads
Best for APIs, real-time, microservices Data science, scripts Systems, CLIs Enterprise
Learning curve Low (if you know JS) Low Medium High
npm packages 2M+ PyPI 500k+ Limited Maven Central 550k+

1. Installation and Setup

Install Node.js

Go to nodejs.org and download the LTS version (Long Term Support — stable and recommended).

Verify installation:

node --version    # v22.x.x (or similar)
npm --version     # 10.x.x (comes bundled with Node)

Your first Node.js script

Create a file hello.js:

console.log("Hello, Node.js!");
console.log("Node version:", process.version);
console.log("Platform:", process.platform);

Run it:

node hello.js
# Hello, Node.js!
# Node version: v22.6.0
# Platform: linux

That's it — JavaScript running outside the browser.

The REPL (interactive shell)

node
> 2 + 2
4
> "hello".toUpperCase()
'HELLO'
> .exit

2. Node.js vs Browser JavaScript

Node.js is JavaScript, but some things are different:

Feature Browser Node.js
window / document ❌ (no DOM)
process object
File system access ✅ (fs module)
Network (raw TCP) Limited ✅ (net module)
fetch ✅ (built-in since Node 18)
ES modules ✅ (plus CommonJS require)
console.log

3. Modules

Node.js has two module systems. CommonJS (older, still widely used) and ES Modules (modern, same as browsers).

CommonJS (require / module.exports)

// math.js
function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

module.exports = { add, multiply };
// main.js
const { add, multiply } = require("./math");

console.log(add(3, 4));       // 7
console.log(multiply(3, 4));  // 12

ES Modules (import / export)

Add "type": "module" to package.json, or use .mjs file extension.

// math.mjs
export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}
// main.mjs
import { add, multiply } from "./math.mjs";

console.log(add(3, 4));       // 7
console.log(multiply(3, 4));  // 12

CommonJS vs ES Modules

CommonJS ES Modules
Syntax require() / module.exports import / export
Loading Synchronous Asynchronous
File extension .js (default) .mjs or "type": "module"
Dynamic import Supported import() function
Tree-shaking ✅ (bundlers can optimize)
When to use Legacy projects, Node scripts Modern apps, bundlers

Built-in modules

Node.js ships with many useful modules — no installation needed:

Module Purpose Example
fs File system Read/write files
path Path manipulation Join, resolve paths
http HTTP server Create raw web server
https HTTPS support Secure connections
os Operating system info Platform, CPU, memory
events Event emitter Custom events
stream Streams Large data processing
crypto Cryptography Hashing, encryption
child_process Run system commands exec, spawn
url URL parsing Parse and format URLs
util Utilities promisify, inspect
net TCP/socket Raw TCP connections

4. npm (Node Package Manager)

npm is the world's largest software registry with 2M+ packages.

Initialize a project

mkdir my-project
cd my-project
npm init -y       # creates package.json with defaults

package.json

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "My Node.js project",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "node --watch index.js"
  },
  "dependencies": {},
  "devDependencies": {}
}

Installing packages

npm install express           # install and save to dependencies
npm install -D nodemon        # install as devDependency
npm install                   # install all dependencies from package.json
npm uninstall express         # remove package
npm update                    # update packages
npm list                      # list installed packages

npm scripts

npm start            # runs "start" script in package.json
npm run dev          # runs "dev" script
npm test             # runs "test" script

Key concepts

Term Meaning
dependencies Packages needed to run the app
devDependencies Packages only needed during development
node_modules/ Where packages are installed (never commit this)
package-lock.json Exact versions of every installed package
.npmrc npm configuration file

Always add node_modules/ to .gitignore:

node_modules/
.env

5. File System (fs module)

The fs module lets you read, write, and manage files.

Read a file

const fs = require("fs");

// Synchronous (blocks execution)
const content = fs.readFileSync("file.txt", "utf8");
console.log(content);

// Asynchronous (recommended)
fs.readFile("file.txt", "utf8", (err, data) => {
  if (err) throw err;
  console.log(data);
});

Write a file

const fs = require("fs");

// Write (creates or overwrites)
fs.writeFileSync("output.txt", "Hello, file!");

// Append
fs.appendFileSync("output.txt", "\nNew line");

// Async version
fs.writeFile("output.txt", "Hello!", (err) => {
  if (err) throw err;
  console.log("File written");
});

fs/promises (modern async approach)

const fs = require("fs/promises");

async function main() {
  // Read
  const content = await fs.readFile("file.txt", "utf8");
  console.log(content);

  // Write
  await fs.writeFile("output.txt", "Hello!");

  // Read directory
  const files = await fs.readdir("./");
  console.log(files);

  // Check if file exists
  try {
    await fs.access("file.txt");
    console.log("File exists");
  } catch {
    console.log("File not found");
  }
}

main();

Path module

const path = require("path");

path.join("folder", "subfolder", "file.txt");  // folder/subfolder/file.txt
path.resolve("./file.txt");                     // absolute path
path.extname("file.txt");                       // .txt
path.basename("/path/to/file.txt");             // file.txt
path.dirname("/path/to/file.txt");              // /path/to
path.parse("/path/to/file.txt");
// { root: '/', dir: '/path/to', base: 'file.txt', ext: '.txt', name: 'file' }

6. Async Programming

Node.js is built around asynchronous, non-blocking I/O. Understanding async patterns is essential.

The event loop (simplified)

Node.js is single-threaded but handles many concurrent operations via the event loop:

  1. JavaScript runs synchronously
  2. Async operations (file I/O, network) are offloaded to the OS
  3. When complete, callbacks are queued
  4. Event loop picks them up and runs them

This means Node.js can handle thousands of concurrent connections without threads.

Callbacks (old style)

const fs = require("fs");

fs.readFile("a.txt", "utf8", (err, dataA) => {
  if (err) return console.error(err);

  fs.readFile("b.txt", "utf8", (err, dataB) => {
    if (err) return console.error(err);

    console.log(dataA + dataB);
    // This "callback hell" nesting is why Promises exist
  });
});

Promises

const fs = require("fs/promises");

fs.readFile("a.txt", "utf8")
  .then((dataA) => {
    return fs.readFile("b.txt", "utf8").then((dataB) => dataA + dataB);
  })
  .then((combined) => console.log(combined))
  .catch((err) => console.error(err));

// Parallel reads (both start at the same time)
Promise.all([
  fs.readFile("a.txt", "utf8"),
  fs.readFile("b.txt", "utf8"),
]).then(([dataA, dataB]) => {
  console.log(dataA + dataB);
});

async/await (recommended)

const fs = require("fs/promises");

async function readBothFiles() {
  try {
    // Sequential
    const dataA = await fs.readFile("a.txt", "utf8");
    const dataB = await fs.readFile("b.txt", "utf8");
    console.log(dataA + dataB);

    // Parallel (faster)
    const [fileA, fileB] = await Promise.all([
      fs.readFile("a.txt", "utf8"),
      fs.readFile("b.txt", "utf8"),
    ]);
    console.log(fileA + fileB);
  } catch (err) {
    console.error("Error:", err.message);
  }
}

readBothFiles();

util.promisify

Convert old callback-style functions to Promises:

const { promisify } = require("util");
const fs = require("fs");

const readFile = promisify(fs.readFile);

async function main() {
  const content = await readFile("file.txt", "utf8");
  console.log(content);
}

7. HTTP Module (raw server)

const http = require("http");

const server = http.createServer((req, res) => {
  const { method, url } = req;

  if (method === "GET" && url === "/") {
    res.writeHead(200, { "Content-Type": "text/html" });
    res.end("<h1>Hello, Node.js!</h1>");
  } else if (method === "GET" && url === "/api/hello") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ message: "Hello from Node.js API" }));
  } else {
    res.writeHead(404, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ error: "Not found" }));
  }
});

server.listen(3000, () => {
  console.log("Server running at http://localhost:3000");
});

The raw http module works, but for real apps you'll use Express.


8. Express.js (web framework)

Express is the most popular Node.js web framework — minimal, flexible, and widely used.

Install Express

npm install express

Hello World with Express

const express = require("express");
const app = express();

app.use(express.json()); // parse JSON request bodies

app.get("/", (req, res) => {
  res.send("Hello, Express!");
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

Route methods

app.get("/users", (req, res) => { ... });     // GET
app.post("/users", (req, res) => { ... });    // POST
app.put("/users/:id", (req, res) => { ... }); // PUT
app.patch("/users/:id", (req, res) => { ... }); // PATCH
app.delete("/users/:id", (req, res) => { ... }); // DELETE

Route parameters and query strings

// Route parameter: /users/42
app.get("/users/:id", (req, res) => {
  const { id } = req.params; // "42"
  res.json({ id, name: "Alice" });
});

// Query string: /search?q=node&limit=10
app.get("/search", (req, res) => {
  const { q, limit = 20 } = req.query;
  res.json({ query: q, limit: Number(limit) });
});

Request body

// POST /users  with body: { "name": "Alice", "email": "alice@example.com" }
app.post("/users", (req, res) => {
  const { name, email } = req.body;

  if (!name || !email) {
    return res.status(400).json({ error: "name and email required" });
  }

  const user = { id: Date.now(), name, email };
  res.status(201).json(user);
});

Middleware

Middleware functions run between the request and the response:

// Logging middleware
function logger(req, res, next) {
  console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
  next(); // call next() to continue
}

// Error handling middleware (4 parameters)
function errorHandler(err, req, res, next) {
  console.error(err.stack);
  res.status(500).json({ error: "Internal server error" });
}

app.use(logger); // apply to all routes

app.get("/", (req, res) => {
  res.send("Hello!");
});

app.use(errorHandler); // must be last

Common middleware packages

npm install cors helmet morgan
const cors = require("cors");
const helmet = require("helmet");
const morgan = require("morgan");

app.use(cors());            // enable CORS for all origins
app.use(helmet());          // set security HTTP headers
app.use(morgan("combined")); // HTTP request logger

9. Building a REST API

A complete CRUD REST API for a todo list (in-memory, no database):

const express = require("express");
const app = express();

app.use(express.json());

// In-memory "database"
let todos = [
  { id: 1, title: "Learn Node.js", done: false },
  { id: 2, title: "Build an API", done: false },
];
let nextId = 3;

// GET /todos — list all
app.get("/todos", (req, res) => {
  res.json(todos);
});

// GET /todos/:id — get one
app.get("/todos/:id", (req, res) => {
  const todo = todos.find((t) => t.id === Number(req.params.id));
  if (!todo) return res.status(404).json({ error: "Not found" });
  res.json(todo);
});

// POST /todos — create
app.post("/todos", (req, res) => {
  const { title } = req.body;
  if (!title) return res.status(400).json({ error: "title is required" });

  const todo = { id: nextId++, title, done: false };
  todos.push(todo);
  res.status(201).json(todo);
});

// PUT /todos/:id — update
app.put("/todos/:id", (req, res) => {
  const index = todos.findIndex((t) => t.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ error: "Not found" });

  const { title, done } = req.body;
  todos[index] = { ...todos[index], ...(title && { title }), ...(done !== undefined && { done }) };
  res.json(todos[index]);
});

// DELETE /todos/:id — delete
app.delete("/todos/:id", (req, res) => {
  const index = todos.findIndex((t) => t.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ error: "Not found" });

  todos.splice(index, 1);
  res.status(204).send();
});

app.listen(3000, () => console.log("API running on http://localhost:3000"));

Test with curl:

curl http://localhost:3000/todos
curl -X POST http://localhost:3000/todos -H "Content-Type: application/json" -d '{"title":"Buy groceries"}'
curl -X PUT http://localhost:3000/todos/3 -H "Content-Type: application/json" -d '{"done":true}'
curl -X DELETE http://localhost:3000/todos/3

10. Environment Variables

Never hardcode secrets. Use environment variables.

# .env file (never commit this)
PORT=3000
DATABASE_URL=postgres://localhost:5432/mydb
API_KEY=secret123
npm install dotenv
require("dotenv").config(); // load .env file

const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;

console.log(`Listening on port ${port}`);

Access environment variables:

process.env.NODE_ENV    // "development", "production", "test"
process.env.PORT        // "3000" (always a string)
process.env.MY_SECRET   // your secret value

11. Error Handling

Synchronous errors

try {
  const data = JSON.parse("invalid json");
} catch (err) {
  console.error("Parse error:", err.message);
}

Async errors with async/await

async function fetchUser(id) {
  const res = await fetch(`https://api.example.com/users/${id}`);

  if (!res.ok) {
    throw new Error(`HTTP error: ${res.status}`);
  }

  return res.json();
}

// Always wrap await in try/catch
async function main() {
  try {
    const user = await fetchUser(1);
    console.log(user);
  } catch (err) {
    console.error("Failed to fetch user:", err.message);
  }
}

Express async error handling

Express doesn't catch async errors automatically. Use a wrapper or pass errors to next:

// Option 1: try/catch in every route
app.get("/users/:id", async (req, res) => {
  try {
    const user = await getUserById(req.params.id);
    res.json(user);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Option 2: async wrapper function
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

app.get("/users/:id", asyncHandler(async (req, res) => {
  const user = await getUserById(req.params.id);
  res.json(user);
}));

// Global error handler (add at the end)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: "Internal server error" });
});

Unhandled promise rejections

process.on("unhandledRejection", (reason, promise) => {
  console.error("Unhandled rejection:", reason);
  process.exit(1);
});

process.on("uncaughtException", (err) => {
  console.error("Uncaught exception:", err);
  process.exit(1);
});

12. Working with JSON

JSON is the primary data format for Node.js APIs.

// Parse JSON string → JavaScript object
const jsonString = '{"name":"Alice","age":30}';
const user = JSON.parse(jsonString);
console.log(user.name); // Alice

// Serialize JavaScript object → JSON string
const obj = { name: "Bob", age: 25, tags: ["dev", "node"] };
const json = JSON.stringify(obj);           // compact
const pretty = JSON.stringify(obj, null, 2); // pretty-printed

// Read JSON file
const fs = require("fs");
const config = JSON.parse(fs.readFileSync("config.json", "utf8"));

// Write JSON file
fs.writeFileSync("output.json", JSON.stringify(data, null, 2));

13. Streams

Streams are for processing large data efficiently — without loading everything into memory.

const fs = require("fs");
const { Transform } = require("stream");

// Read a large file line by line
const readline = require("readline");

const rl = readline.createInterface({
  input: fs.createReadStream("large-file.txt"),
  crlfDelay: Infinity,
});

rl.on("line", (line) => {
  console.log("Line:", line);
});

rl.on("close", () => {
  console.log("Done reading");
});

// Pipe streams (read → transform → write)
const upperCase = new Transform({
  transform(chunk, encoding, callback) {
    callback(null, chunk.toString().toUpperCase());
  },
});

fs.createReadStream("input.txt")
  .pipe(upperCase)
  .pipe(fs.createWriteStream("output.txt"));

14. Events (EventEmitter)

Node.js is built on the event-driven architecture using EventEmitter.

const { EventEmitter } = require("events");

const emitter = new EventEmitter();

// Listen for an event
emitter.on("data", (payload) => {
  console.log("Received data:", payload);
});

emitter.once("connect", () => {
  console.log("Connected! (fires only once)");
});

// Emit events
emitter.emit("connect");
emitter.emit("data", { user: "Alice", action: "login" });
emitter.emit("data", { user: "Bob", action: "logout" });

// Custom class extending EventEmitter
class FileWatcher extends EventEmitter {
  constructor(filename) {
    super();
    this.filename = filename;
  }

  start() {
    const fs = require("fs");
    fs.watchFile(this.filename, (curr, prev) => {
      if (curr.mtime !== prev.mtime) {
        this.emit("change", this.filename);
      }
    });
  }
}

const watcher = new FileWatcher("config.json");
watcher.on("change", (file) => console.log(`${file} changed`));
watcher.start();

15. Making HTTP Requests

Using built-in fetch (Node.js 18+)

// GET request
const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");
const post = await res.json();
console.log(post.title);

// POST request
const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Hello", body: "World", userId: 1 }),
});
const created = await response.json();
console.log(created.id);

Using axios (popular npm package)

npm install axios
const axios = require("axios");

// GET
const { data } = await axios.get("https://api.example.com/users");
console.log(data);

// POST
const response = await axios.post("https://api.example.com/users", {
  name: "Alice",
  email: "alice@example.com",
});
console.log(response.data);

// With headers and error handling
try {
  const { data } = await axios.get("https://api.example.com/protected", {
    headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
  });
  console.log(data);
} catch (err) {
  if (err.response) {
    console.error("HTTP error:", err.response.status);
  } else {
    console.error("Network error:", err.message);
  }
}

16. Project Structure

A well-organized Node.js/Express project:

my-api/
├── src/
│   ├── routes/
│   │   ├── users.js       # /users routes
│   │   └── todos.js       # /todos routes
│   ├── controllers/
│   │   ├── users.js       # business logic for users
│   │   └── todos.js       # business logic for todos
│   ├── middleware/
│   │   ├── auth.js        # authentication middleware
│   │   └── errorHandler.js
│   ├── models/
│   │   └── user.js        # data models / schemas
│   └── app.js             # express app setup (no listen)
├── index.js               # entry point (app.listen)
├── .env                   # environment variables
├── .gitignore
└── package.json
// src/app.js
const express = require("express");
const cors = require("cors");
const userRoutes = require("./routes/users");
const todoRoutes = require("./routes/todos");
const errorHandler = require("./middleware/errorHandler");

const app = express();

app.use(cors());
app.use(express.json());

app.use("/api/users", userRoutes);
app.use("/api/todos", todoRoutes);

app.use(errorHandler);

module.exports = app;
// index.js
const app = require("./src/app");

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

17. Three Beginner Projects

Project 1: CLI Todo Manager

// todo-cli.js
const fs = require("fs");
const path = require("path");

const DB_FILE = path.join(__dirname, "todos.json");

function loadTodos() {
  if (!fs.existsSync(DB_FILE)) return [];
  return JSON.parse(fs.readFileSync(DB_FILE, "utf8"));
}

function saveTodos(todos) {
  fs.writeFileSync(DB_FILE, JSON.stringify(todos, null, 2));
}

const [,, command, ...args] = process.argv;
const todos = loadTodos();

switch (command) {
  case "add": {
    const title = args.join(" ");
    if (!title) { console.log("Usage: node todo-cli.js add <title>"); break; }
    const todo = { id: Date.now(), title, done: false };
    todos.push(todo);
    saveTodos(todos);
    console.log(`Added: ${title}`);
    break;
  }

  case "list": {
    if (todos.length === 0) { console.log("No todos yet!"); break; }
    todos.forEach((t, i) => {
      console.log(`${i + 1}. [${t.done ? "x" : " "}] ${t.title}`);
    });
    break;
  }

  case "done": {
    const index = Number(args[0]) - 1;
    if (!todos[index]) { console.log("Todo not found"); break; }
    todos[index] = { ...todos[index], done: true };
    saveTodos(todos);
    console.log(`Done: ${todos[index].title}`);
    break;
  }

  case "delete": {
    const index = Number(args[0]) - 1;
    if (!todos[index]) { console.log("Todo not found"); break; }
    const [removed] = todos.splice(index, 1);
    saveTodos(todos);
    console.log(`Deleted: ${removed.title}`);
    break;
  }

  default:
    console.log("Commands: add <title> | list | done <n> | delete <n>");
}

Usage:

node todo-cli.js add "Learn Node.js"
node todo-cli.js add "Build an API"
node todo-cli.js list
node todo-cli.js done 1
node todo-cli.js delete 2

Project 2: REST API with Express and File Storage

// server.js
const express = require("express");
const fs = require("fs");

const app = express();
app.use(express.json());

const DB_FILE = "notes.json";

function readNotes() {
  if (!fs.existsSync(DB_FILE)) return [];
  return JSON.parse(fs.readFileSync(DB_FILE, "utf8"));
}

function writeNotes(notes) {
  fs.writeFileSync(DB_FILE, JSON.stringify(notes, null, 2));
}

// List all notes
app.get("/notes", (req, res) => {
  res.json(readNotes());
});

// Get one note
app.get("/notes/:id", (req, res) => {
  const notes = readNotes();
  const note = notes.find((n) => n.id === req.params.id);
  if (!note) return res.status(404).json({ error: "Not found" });
  res.json(note);
});

// Create note
app.post("/notes", (req, res) => {
  const { title, content } = req.body;
  if (!title) return res.status(400).json({ error: "title required" });

  const notes = readNotes();
  const note = {
    id: Date.now().toString(),
    title,
    content: content || "",
    createdAt: new Date().toISOString(),
  };
  notes.push(note);
  writeNotes(notes);
  res.status(201).json(note);
});

// Update note
app.put("/notes/:id", (req, res) => {
  const notes = readNotes();
  const index = notes.findIndex((n) => n.id === req.params.id);
  if (index === -1) return res.status(404).json({ error: "Not found" });

  notes[index] = { ...notes[index], ...req.body, id: notes[index].id };
  writeNotes(notes);
  res.json(notes[index]);
});

// Delete note
app.delete("/notes/:id", (req, res) => {
  const notes = readNotes();
  const index = notes.findIndex((n) => n.id === req.params.id);
  if (index === -1) return res.status(404).json({ error: "Not found" });

  notes.splice(index, 1);
  writeNotes(notes);
  res.status(204).send();
});

app.listen(3000, () => console.log("Notes API on http://localhost:3000"));

Project 3: File Processing Script

Process a CSV file and output statistics:

// analyze-csv.js
const fs = require("fs");
const readline = require("readline");

async function analyzeCsv(filename) {
  const rl = readline.createInterface({
    input: fs.createReadStream(filename),
    crlfDelay: Infinity,
  });

  const rows = [];
  let headers = null;

  for await (const line of rl) {
    if (!headers) {
      headers = line.split(",").map((h) => h.trim());
    } else {
      const values = line.split(",").map((v) => v.trim());
      const row = {};
      headers.forEach((h, i) => {
        row[h] = values[i] || "";
      });
      rows.push(row);
    }
  }

  console.log(`Rows: ${rows.length}`);
  console.log(`Columns: ${headers.join(", ")}`);

  // Numeric column stats
  headers.forEach((header) => {
    const values = rows
      .map((r) => parseFloat(r[header]))
      .filter((v) => !isNaN(v));

    if (values.length > 0) {
      const sum = values.reduce((a, b) => a + b, 0);
      const avg = sum / values.length;
      const min = Math.min(...values);
      const max = Math.max(...values);
      console.log(`${header}: avg=${avg.toFixed(2)}, min=${min}, max=${max}`);
    }
  });
}

const file = process.argv[2];
if (!file) {
  console.log("Usage: node analyze-csv.js <file.csv>");
  process.exit(1);
}

analyzeCsv(file).catch(console.error);

Learning path

Stage Topics Time
1. Foundation JavaScript basics, Node install, REPL Week 1
2. Core Node Modules, fs, path, environment vars Week 2
3. Async Callbacks → Promises → async/await Week 2-3
4. Express Routing, middleware, REST API Week 3-4
5. Data JSON, file storage, then a real DB (SQLite/PostgreSQL) Month 2
6. Production Error handling, logging, env config, Docker Month 2-3
7. Advanced Streams, EventEmitter, testing, auth (JWT) Month 3-4

Common mistakes

Mistake Problem Fix
Forgetting await Promise returned instead of value Add await before async calls
No error handling in async routes Unhandled rejection crashes server Use try/catch or asyncHandler wrapper
Committing node_modules/ Huge repo, unnecessary Add to .gitignore
Committing .env Exposes secrets Add to .gitignore, use .env.example
require path without ./ Looks for npm package, not local file Always require("./myfile") for local
Calling res.json() twice "Cannot set headers after they are sent" return res.json(...) to stop execution
Synchronous fs in production Blocks event loop Use async fs/promises or callbacks
No process.env validation Silent missing config Check required env vars at startup

Node.js vs related technologies

Term What it is
Node.js JavaScript runtime (V8 engine + I/O APIs)
npm Default package manager bundled with Node
pnpm Faster alternative package manager
Bun Faster JS runtime, drop-in Node alternative
Deno Secure JS runtime by Node's creator, TypeScript first
Express Minimal Node.js web framework
Fastify Fast, schema-based Node.js web framework
NestJS Opinionated Node.js framework (Angular-style)
Next.js React framework with Node.js backend (App Router)
V8 JavaScript engine (from Chrome) that powers Node.js

Frequently asked questions

Do I need to know JavaScript before learning Node.js?
Yes — Node.js is JavaScript. Learn JS basics first (variables, functions, arrays, objects, async/await). Then Node.js becomes straightforward.

Node.js vs Python for backend — which should I learn?
If you already know JavaScript, Node.js is the obvious choice. Python is better if you're interested in data science or ML alongside backend. Both are excellent for web APIs.

Is Node.js good for production?
Yes. Node.js powers Netflix, PayPal, LinkedIn, Uber, and millions of other production apps. It excels at I/O-heavy workloads (APIs, real-time, microservices).

When should I use Express vs NestJS vs Fastify?
Express: learning, small projects, maximum flexibility. Fastify: performance-critical APIs with schema validation. NestJS: large teams, enterprise projects, Angular-like structure with TypeScript.

What database works best with Node.js?
All major databases have Node.js drivers. Common choices: PostgreSQL (pg / Prisma / Drizzle), MongoDB (mongoose), SQLite (better-sqlite3 for scripts), Redis (ioredis for caching).

How do I deploy a Node.js app?
Options: Railway, Render, or Fly.io (easiest), Heroku, DigitalOcean App Platform, AWS EC2/ECS/Lambda, Google Cloud Run, or any VPS with PM2 as a process manager.

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools