Node.js Part 1: What Is Node.js and How to Build Your First Node.js App

Node.js Part 1 banner: What Is Node.js? Your First Node.js App, with the event loop handling files, network and database
PART 1 Node.js Series · DevDojo What Is Node.js? Your First Node.js App Runtime, event loop and your first web server JS Requests Event loop File system Network Database Never waits, always busy devdojo.co.in · Beginner friendly · Works on Node.js 22, 24 and 26
Series: Node.js Part 1 of 30

What you should know first: this is the first part, so no earlier part is needed. You should know basic JavaScript (variables, functions, arrays, objects and arrow functions). If promises still feel new, keep our JavaScript Promises guide open for later parts.

If you have written JavaScript for the browser, you already know half of backend development. Node.js lets the same language run outside the browser: on your laptop, on a server, inside build tools and in the cloud. In this first part of the Node.js series you will learn, in simple words, what is Node.js, how it is different from browser JavaScript, and why its “never wait” design makes it so good for web servers and APIs. Then you will install it, write your first scripts, and build a small web server with zero packages.

Quick Summary
  • Node.js is a free, open-source JavaScript runtime: a program that runs JavaScript outside the browser, built on Google’s V8 engine.
  • It adds what servers need and browsers do not have: files (fs), network servers (http), the operating system (os, process) and the huge npm package library.
  • Node.js is non-blocking: slow work (files, network, databases) runs in the background, and the event loop runs your callback when the result is ready. One process can serve thousands of users.
  • Install the LTS (long-term support) version, then run a file with node hello.js.
  • A web server needs only the built-in node:http module; node --watch restarts it whenever you save.
Full Node.js roadmap (30 parts)

Beginner

  1. What Is Node.js and How to Build Your First Node.js App You are here
  2. Modules in Node.js: ES Modules, CommonJS and import/export Coming soon
  3. npm and package.json: Installing and Managing Packages Coming soon
  4. Working with Files and Folders: the fs and path Modules Coming soon
  5. Asynchronous Node.js: Callbacks, Promises and async/await Coming soon
  6. The Event Loop Explained Simply Coming soon
  7. Events and EventEmitter: Building Event-Driven Code Coming soon
  8. Streams and Buffers: Handling Large Data Efficiently Coming soon
  9. Building a Web Server with the http Module Coming soon
  10. Mini Project: Build a Command-Line Tool with Node.js Coming soon

Intermediate

  1. Express.js Basics: Routes, Requests and Responses Coming soon
  2. Middleware in Express: How Requests Flow Coming soon
  3. Build a REST API with Express: Full CRUD Coming soon
  4. Validating Request Data with Zod Coming soon
  5. Environment Variables and Configuration (–env-file and .env) Coming soon
  6. Connecting Node.js to PostgreSQL Coming soon
  7. Using an ORM: Prisma vs Drizzle Coming soon
  8. MongoDB with Mongoose Coming soon
  9. Authentication: Password Hashing, Sessions and JWT Coming soon
  10. Error Handling and Logging with Pino Coming soon

Advanced

  1. Testing Node.js Apps with node:test and Supertest Coming soon
  2. TypeScript with Node.js: Running .ts Files Directly Coming soon
  3. File Uploads and Image Processing Coming soon
  4. Real-Time Apps with WebSockets and Socket.IO Coming soon
  5. Caching with Redis Coming soon
  6. Background Jobs and Queues with BullMQ Coming soon
  7. Worker Threads and Clustering for Performance Coming soon
  8. Security Best Practices for Node.js APIs Coming soon
  9. Debugging, Profiling and Performance Tuning Coming soon
  10. Final Project: Build and Deploy a Production-Ready Node.js API Coming soon

What is Node.js? (simple definition)

Node.js is a JavaScript runtime. A runtime is the environment that actually runs your code. Before Node.js, the only place JavaScript could run was inside a web browser. In 2009 Ryan Dahl took V8, the very fast JavaScript engine from Google Chrome, and wrapped it in a program that can run on any computer and talk to the file system and the network. That program is Node.js.

In one line: Node.js lets you run JavaScript on a computer or server (not just in a browser), so you can build backends, APIs, command-line tools and much more with one language.

Three words help you understand it:

Runtime, not a languageThe language is still JavaScript. Node.js is the place where it runs, like the browser is for frontend code.
Not a frameworkNode.js gives you building blocks. Frameworks such as Express, Fastify and NestJS are built on top of it (we will learn them later in this series).
Open sourceNode.js is free and maintained by the OpenJS Foundation and a large community. New major versions arrive regularly; even-numbered ones become LTS.

Node.js is used by companies such as Netflix, PayPal, LinkedIn, Uber, Walmart and many Indian startups and product companies for APIs and web servers. It also powers almost every modern frontend tool: Vite, Next.js, ESLint and TypeScript all run on Node.js. So even frontend developers use it every day. The official site nodejs.org/learn has a good free introduction too.

Browser JavaScript vs Node.js

The language is the same: let, const, functions, arrays, objects, promises and async/await all work exactly as you know them. What changes is the toolbox around the language.

Browser Node.js JavaScript engine (V8, etc.) V8 engine + libuv DOM, document window, alert() localStorage fetch(), timers Files (fs) Web servers (http) OS, process fetch(), timers Runs on the user’s device, sandboxed Runs on your computer or server
Same language, different toolbox: the browser gives JavaScript the page, Node.js gives it files, servers and the operating system.
TopicBrowserNode.js
Where it runsOn the visitor’s device, inside a tabOn your computer or a server
Main jobShow pages and react to clicksServe APIs, read files, talk to databases, run tools
Special objectsdocument, window, localStorageprocess, fs, http, os, path
Access to filesNo (only files the user picks)Yes, full access to the file system
Who controls the versionThe user’s browserYou do, so you can use the newest features
PackagesBundled by tools like ViteInstalled with npm and imported directly
Good news: modern Node.js also has many browser APIs built in, like fetch(), URL, setTimeout, structuredClone and Web Streams. Code you learned for the browser often works in Node.js without changes.

How Node.js works: the event loop in simple words

Think of a busy restaurant with one very fast waiter. The waiter takes your order, gives it to the kitchen, and immediately goes to the next table. They do not stand in the kitchen waiting for your food. When a dish is ready, the kitchen rings a bell and the waiter delivers it.

Node.js works the same way:

  • Your JavaScript runs on one main thread (the waiter). It runs one piece of code at a time.
  • Slow work is handed off (to the kitchen). Reading a file, calling another API or querying a database is done by the operating system and a C library called libuv, in the background.
  • Finished work waits in a queue (the bell). Each finished job has a callback, a function you gave Node.js to run “when it is done”.
  • The event loop delivers results. Whenever the main thread is free, the event loop takes the next callback from the queue and runs it.
1. Your code one main thread console.log(“1”) readFile(…) setTimeout(…) console.log(“2”) 2. Slow work done by the OS and libuv reading a file… waiting for a timer… database query… 3. Callback queue finished jobs wait here timer done → run file ready → run The event loop: when the main thread is free, run the next waiting callback
Node.js never sits idle waiting for a file or the network. It hands slow work to the system and keeps running your code; the event loop runs each callback when its result is ready.

This style is called non-blocking I/O (I/O means input/output: files, network, databases). Because the main thread never waits, a single Node.js process can handle thousands of users at the same time, as long as each request does mostly I/O and not heavy number crunching.

The one rule to remember: never block the main thread. A long for loop that runs for 5 seconds freezes every user on your server for 5 seconds. Heavy CPU work belongs in worker threads or a separate service (we cover this in Part 27).

We will study the event loop deeply in Part 6. For now, the restaurant picture is all you need.

What can you build with Node.js?

REST and GraphQL APIsThe backend for web and mobile apps: login, payments, orders, search.
Real-time appsChat, live dashboards, multiplayer games and notifications with WebSockets.
Full-stack web appsNext.js, Nuxt and Remix run their server parts on Node.js.
Command-line toolsScripts and CLIs like npm, vite and eslint.
Automation and AI agentsBots, scrapers, cron jobs and LLM-powered tools that call APIs.
MicroservicesSmall services in Docker containers, deployed with CI/CD pipelines.

Install Node.js (choose the LTS version)

On nodejs.org/download you will see two kinds of versions. LTS (Long Term Support) gets bug and security fixes for about 30 months, which is why companies use it in production. Current has the newest features but changes faster. As a beginner, always pick LTS. Everything in this series works on Node.js 22, 24 and 26.

The easiest way on Windows is the official LTS installer from nodejs.org. It also installs npm and adds node to your PATH. If you like the terminal, winget does the same in one command.

Windows PowerShell
# Option 1: download the LTS installer from nodejs.org and click Next
# Option 2: use winget (built into Windows 10 and 11)
$ winget install OpenJS.NodeJS.LTS
# Close and reopen the terminal, then check:
$ node -v
$ npm -v

On a Mac we recommend nvm. It lets you install many Node.js versions side by side and switch between them, which you will need when different projects use different versions.

macOS — zsh
# Install nvm (check github.com/nvm-sh/nvm for the newest version)
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# Restart the terminal, then install the latest LTS version
$ nvm install --lts
$ nvm use --lts
$ node -v

On Ubuntu, Debian or WSL, skip the old apt install nodejs package (it is often years behind). Use nvm instead:

Ubuntu — bash
# Same nvm steps work on Linux and WSL
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
$ source ~/.bashrc
$ nvm install --lts
$ node -v
# Switch versions any time, per project
$ nvm install 24
$ nvm use 24

Pick your operating system above to see the right install steps.

Now open a new terminal and check that both node and npm (the package manager that comes with Node.js) are ready. Your version numbers may be newer; that is fine.

node-part1 — bash
# Check that Node.js and npm are installed
$ node -v
v22.22.0
$ npm -v
10.9.4

Try the Node.js REPL (a JavaScript playground)

Type node with no file name and you enter the REPL (Read, Evaluate, Print, Loop). It reads a line of JavaScript, runs it, prints the result and waits for the next line. It is perfect for quick experiments.

node — REPL
$ node
Welcome to Node.js v22.22.0.
Type ".help" for more information.
> 2 + 3
5
> "devdojo".toUpperCase()
'DEVDOJO'
> [1, 2, 3].map(n => n * 2)
[ 2, 4, 6 ]
> .exit

Press Ctrl + C twice or type .exit to leave. Use the REPL to test small ideas; use files for real programs.

Your first Node.js script

Create a folder called node-part1, open it in VS Code, and create a file named hello.js. This script greets you and prints some facts about your machine, things a browser is not allowed to tell a web page.

hello.js — node-part1 — Visual Studio Code
node-part1 › hello.js
// hello.js – your first Node.js program
import os from "node:os";

const name = process.argv[2] ?? "DevDojo reader";

console.log(`Hello, ${name}!`);
console.log("Node.js version:", process.version);
console.log("Operating system:", os.platform());
console.log("CPU cores:", os.cpus().length);
TERMINALOUTPUTPROBLEMSReal output (Node.js 22, Linux)
$ node hello.js Lokendra
Hello, Lokendra!
Node.js version: v22.22.0
Operating system: linux
CPU cores: 2
⎇ mainLn 9, Col 1Spaces: 2UTF-8LFJavaScript

Click ▶ Run to see the real output in the terminal panel.

Let’s read it line by line:

  • import os from "node:os" loads a built-in module. The node: prefix makes it clear this is part of Node.js itself, not an npm package. (To use import in a .js file, add "type": "module" to package.json; we do that below. Recent Node.js versions also detect it automatically.)
  • process is a global object about the running program. process.argv is the list of words you typed in the terminal, so process.argv[2] is the first extra word (Lokendra).
  • ?? gives a default value when nothing was typed.
  • process.version, os.platform() and os.cpus() read details from the computer.

Run it with node hello.js, then with node hello.js YourName. Congratulations, you have just run JavaScript outside the browser.

See non-blocking code in action

Now let’s prove the restaurant idea with real code. Before you click Run, guess the order in which the five lines will print.

async-demo.js — node-part1 — Visual Studio Code
node-part1 › async-demo.js
// async-demo.js – Node.js does not wait for slow work
import { readFile } from "node:fs/promises";

console.log("1. Start");

setTimeout(() => {
  console.log("4. Timer finished (after 0 ms)");
}, 0);

readFile("package.json", "utf8").then((text) => {
  const pkg = JSON.parse(text);
  console.log(`5. File read: project name is "${pkg.name}"`);
});

console.log("2. Asked for the timer and the file");
console.log("3. Still running other code...");
TERMINALOUTPUTPROBLEMSReal output (Node.js 22)
$ node async-demo.js
1. Start
2. Asked for the timer and the file
3. Still running other code...
4. Timer finished (after 0 ms)
5. File read: project name is "node-part1"
⎇ mainLn 16, Col 1Spaces: 2UTF-8LFJavaScript

Make your guess, then click ▶ Run.

Even with a delay of 0 ms, the timer message prints after lines 2 and 3. Here is why:

  1. Node.js runs all the normal code from top to bottom first (lines 1, 2, 3).
  2. setTimeout and readFile do not stop the program. They hand the work to the background and register a callback.
  3. Only when the main code is finished does the event loop run the waiting callbacks: first the timer, then the file result once the disk has answered.
Remember: in Node.js, “I asked for it” and “I got it” are two different moments. Every database query and API call you write later works this way. Part 5 covers callbacks, promises and async/await in detail.

Build your first web server with Node.js

This is where Node.js shines. With the built-in node:http module you can build a working web server in about 20 lines, with no npm packages at all. Our server answers three kinds of requests: the home page /, a small JSON API at /api/time, and a 404 page for everything else.

2 files — node-part1 — Visual Studio Code
node-part1 › server.js
// server.js – a tiny web server with no packages at all
import { createServer } from "node:http";

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

const server = createServer((req, res) => {
  if (req.url === "/") {
    res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
    res.end("Hello from Node.js!\n");
  } else if (req.url === "/api/time") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ time: new Date().toISOString() }));
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.end("Page not found\n");
  }
});

server.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});
TERMINALOUTPUTPROBLEMSReal output – leave it running
$ node server.js
Server running at http://localhost:3000/
⎇ mainLn 21, Col 1Spaces: 2UTF-8LFJavaScript
node-part1 › client.js
// client.js – call our server with the built-in fetch()
const base = "http://localhost:3000";

const home = await fetch(base + "/");
console.log(home.status, (await home.text()).trim());

const api = await fetch(base + "/api/time");
const data = await api.json();
console.log(api.status, data);

const missing = await fetch(base + "/nope");
console.log(missing.status, (await missing.text()).trim());
TERMINALOUTPUTPROBLEMSReal output (second terminal)
$ node client.js
200 Hello from Node.js!
200 { time: '2026-10-23T13:54:05.642Z' }
404 Page not found
⎇ mainLn 12, Col 1Spaces: 2UTF-8LFJavaScript

Click the server.js and client.js tabs, then ▶ Run on each. Start the server first and keep it running; run the client in a second terminal.

How the server works:

  • createServer() takes a function that runs for every request. It receives req (the request: URL, method, headers) and res (the response you send back).
  • res.writeHead(200, ...) sets the status code and headers. 200 means OK, 404 means not found. The Content-Type header tells the browser what kind of data is coming.
  • res.end(...) sends the body and finishes the response. For JSON we turn an object into text with JSON.stringify.
  • server.listen(PORT) starts listening. process.env.PORT lets a hosting platform choose the port, with 3000 as the local default.

Open http://localhost:3000/ and http://localhost:3000/api/time in your browser too. In client.js we used the built-in fetch() and top-level await (allowed in ES modules) to test the server from code. You can also test with curl http://localhost:3000/.

Is this how real apps are built? Real projects usually use a framework such as Express or Fastify for routing, middleware and validation. But every one of them is built on this same http module, so understanding it now makes those frameworks easy later (Part 11 starts Express).

package.json, npm scripts and –watch

Every Node.js project has a package.json file in its root folder. It stores the project name, version, the packages it needs and handy scripts. Create one with npm init -y (-y means “yes to all defaults”):

node-part1 — bash
# Create a folder and a package.json in one go
$ mkdir node-part1
$ cd node-part1
$ npm init -y
Wrote to /home/you/node-part1/package.json:

{
  "name": "node-part1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Now edit it to look like this. We add "type": "module" so import works in every .js file, and two scripts: start for normal runs and dev for development.

package.json — node-part1 — Visual Studio Code
node-part1 › package.json
{
  "name": "node-part1",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  }
}
⎇ mainLn 9, Col 1Spaces: 2UTF-8LFJSON

Run the scripts from the terminal:

node-part1 — bash
# Run a script from package.json
$ npm run dev
# Or use Node's own faster script runner (Node.js 22+)
$ node --run dev
# Restart automatically when you save a file (no nodemon needed)
$ node --watch server.js
# Stop the server
# press Ctrl + C
  • npm run dev runs the dev script. npm start is a short form for the start script.
  • node --run dev does the same but starts faster because it skips npm (available in Node.js 22 and newer).
  • node --watch restarts the server every time you save a file. You no longer need the old nodemon package for this.
Tip: commit package.json (and later package-lock.json) to Git, but never the node_modules folder. Add node_modules/ to your .gitignore. Part 3 covers npm in depth.

Common Node.js errors and fixes

Every beginner hits these. Bookmark this table; you will see these messages again.

Error messageWhy it happensHow to fix it
'node' is not recognized / command not found: nodeNode.js is not installed, or the terminal was open before installing so PATH was not refreshed.Install the LTS version, then close and reopen the terminal. With nvm, run nvm use --lts.
SyntaxError: Cannot use import statement outside a moduleYou used import in a .js file, but the project is treated as CommonJS.Add "type": "module" to package.json, or rename the file to .mjs.
ReferenceError: require is not defined in ES module scopeYou used old CommonJS require() inside an ES module.Use import fs from "node:fs" instead (or rename the file to .cjs).
ReferenceError: document is not definedBrowser-only objects like document, window and localStorage do not exist in Node.js.Keep DOM code in the browser. In Node.js use modules like fs, http and os.
Error: listen EADDRINUSE: address already in use :::3000Another program (often your old server) is already using port 3000.Stop the old server with Ctrl + C, or start on another port: PORT=4000 node server.js.
Error [ERR_MODULE_NOT_FOUND]: Cannot find moduleWrong file path, missing .js extension in an ES module import, or the package is not installed.Check the path, write ./utils.js (with the extension), and run npm install.

Best practices from day one

  • Use the LTS version and a version manager (nvm, fnm or Volta) so each project can use the version it needs.
  • Use ES modules (import/export with "type": "module"). This is the modern standard and matches browser JavaScript.
  • Write the node: prefix for built-in modules (node:fs, node:http). It is clearer and avoids confusion with npm packages.
  • Never block the event loop. Prefer the async versions of APIs (fs/promises instead of readFileSync) inside servers.
  • Read config from environment variables (like process.env.PORT) instead of hard-coding ports, passwords or API keys.
  • Use node --watch in development and a plain node command in production.
  • Keep secrets out of Git. No API keys in code files. We will set up .env files properly in Part 15.

Practice task

Build a tiny “About me” API. Use only what you learned in this part.

  1. Create a new folder, run npm init -y and add "type": "module" plus a dev script that uses node --watch.
  2. Copy server.js and add a new route /api/me that returns JSON with your name, city and skills (an array).
  3. Add a route /api/system that returns the Node.js version (process.version) and the number of CPU cores (os.cpus().length).
  4. Make the 404 response JSON too: { "error": "Not found", "path": req.url }.
  5. Bonus: change client.js to call all your routes and print the results. Then start the server on port 4000 using PORT=4000 npm run dev.

Frequently asked questions

Is Node.js a programming language?

No. The language is JavaScript. Node.js is a runtime, the program that runs JavaScript outside the browser and gives it access to files, the network and the operating system.

Is Node.js frontend or backend?

Mainly backend: APIs, servers, databases and background jobs. But frontend developers also use Node.js every day, because tools like Vite, Next.js, ESLint and TypeScript run on it.

Is Node.js single-threaded?

Your JavaScript runs on one main thread, but Node.js itself uses extra threads (through libuv) for things like file access, and you can create worker threads for heavy CPU work. That is why one Node.js process can serve many users at once.

Which Node.js version should I install?

The latest LTS version shown on nodejs.org. Use a version manager like nvm so you can switch versions per project. All code in this series works on Node.js 22, 24 and 26.

Node.js vs Python or Java for backend: which is better?

All three are great. Node.js is a strong choice for APIs and real-time apps, and it lets you use one language (JavaScript or TypeScript) on both the frontend and the backend. Python shines in data and AI work, and Java is popular in large enterprise systems.

Is Node.js still worth learning?

Yes. It is one of the most used backend technologies, it has the largest package ecosystem (npm), and it appears in a huge number of backend and full-stack job posts in India and abroad. Preparing for interviews? See our Node.js interview questions.

Conclusion

You now know what Node.js is: a JavaScript runtime built on V8 that runs your code outside the browser and adds files, servers and operating-system access. You learned how it differs from browser JavaScript, how the event loop lets one thread serve many users without waiting, and what you can build with it. You installed Node.js, tried the REPL, wrote your first scripts, saw non-blocking code with your own eyes, built a web server with zero packages, and set up package.json with scripts and --watch.

Want to see where this road leads? Our Docker Compose tutorial runs a Node.js app with PostgreSQL and Redis, and the GitHub Actions CI/CD guide for Node.js shows how to test and deploy it automatically.

Next part – Node.js Part 2: Modules in Node.js: ES Modules, CommonJS and import/export. We will split code into files, learn the difference between import and require(), named vs default exports, and how Node.js finds your modules.

New posts every day on DevDojo

Follow the full Node.js series – 30 parts from “what is Node.js” to building and deploying a production-ready API. Bookmark devdojo.co.in and tell us in the comments what you want to build with Node.js.

Share