Setting Up Your First Node.js Application: A Step-by-Step Guide from Install to HTTP Server

Setting Up Your First Node.js Application: A Step-by-Step Guide from Install to HTTP Server
Audience: This post is for developers who are new to Node.js but comfortable with basic JavaScript. No prior server-side experience required.
TL;DR: Install Node.js, verify it works in your terminal, explore the REPL, write a .js file, run it with the node command, and build a minimal HTTP server using only Node's built-in http module — no Express, no dependencies.
Problem
Most Node.js tutorials start with npm install express before you understand what Node even is. That skips the foundation entirely. Before you use any framework, you need to know: How does Node run JavaScript? What happens when you execute a file? How does it handle an HTTP request at the lowest level?
This post fills that gap.
Solution
We'll go step-by-step through the full setup process — from installing the runtime to serving HTTP responses — using only Node's standard library.
Step 1: Install Node.js
Go to https://nodejs.org and download the LTS (Long Term Support) version. As of 2025, that's Node.js 20.x or 22.x.
Why LTS? LTS releases are supported for 30 months with security and bug fixes. The Current release gets new features faster but isn't recommended for production or learning stability.
OS-neutral options:
- Windows / macOS: Use the official installer from nodejs.org
- Linux (Ubuntu/Debian):
# Using NodeSource repository for the latest LTS
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
- All platforms (recommended for managing versions): Use nvm
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Restart your terminal, then install Node LTS
nvm install --lts
nvm use --lts
Using nvm is the best long-term choice because it lets you switch Node versions per project.
Step 2: Verify the Installation
Open your terminal and run:
node --version
Expected output:
v20.11.1
Also verify npm (Node Package Manager) was installed alongside Node:
npm --version
Expected output:
10.2.4
If either command returns command not found, the installation didn't complete correctly. On Windows, restart your terminal or check that Node's install directory is in your PATH environment variable.
Step 3: Understand and Use the Node REPL
What is the REPL?
REPL stands for Read-Eval-Print Loop. It's an interactive runtime session where Node reads your input, evaluates it as JavaScript, prints the result, and waits for the next input. Think of it as a JavaScript console that runs in your terminal instead of a browser.
It's useful for:
- Testing small expressions quickly
- Exploring built-in modules
- Debugging logic in isolation
Start the REPL:
node
Your prompt changes to >.
Try these inside the REPL:
> 2 + 2
4
> const name = 'Node.js'
> `Hello from ${name}`
'Hello from Node.js'
> typeof process
'object'
> process.version
'v20.11.1'
> process.platform
'linux' // or 'darwin' on macOS, 'win32' on Windows
The process object is global in Node — it gives you runtime information about the current Node process. You'll use it constantly.
To exit the REPL, press Ctrl + C twice or type .exit.
Step 4: Create and Run Your First JavaScript File
Create a directory for your project:
mkdir node-fundamentals
cd node-fundamentals
Create a file called greet.js:
// greet.js
const userName = 'Alice';
const currentHour = new Date().getHours();
let greeting;
if (currentHour < 12) {
greeting = 'Good morning';
} else if (currentHour < 18) {
greeting = 'Good afternoon';
} else {
greeting = 'Good evening';
}
console.log(`${greeting}, ${userName}!`);
console.log(`Node.js version: ${process.version}`);
console.log(`Platform: ${process.platform}`);
Run it:
node greet.js
Expected output (if run in the morning):
Good morning, Alice!
Node.js version: v20.11.1
Platform: linux
What just happened — the execution flow:
greet.js (source file)
|
v
Node.js Runtime
|
|-- V8 Engine parses and compiles the JS
|-- libuv handles I/O (not used here, but available)
|-- process object injected into scope
|
v
stdout (your terminal)
Good morning, Alice!
Node reads the file as a string, passes it to the V8 JavaScript engine (the same engine Chrome uses), executes it synchronously top-to-bottom, writes to stdout via console.log, and exits. No browser, no DOM, no window object — just JavaScript running directly on your machine.
Step 5: Write a Hello World HTTP Server
Node ships with a built-in http module. No installation required. This is the foundation that frameworks like Express are built on.
Create a file called server.js:
// server.js
const http = require('http');
const HOST = '127.0.0.1';
const PORT = 3000;
const server = http.createServer((request, response) => {
const { method, url } = request;
console.log(`[${new Date().toISOString()}] ${method} ${url}`);
// Set response headers
response.setHeader('Content-Type', 'text/plain');
// Route handling without a framework
if (url === '/' && method === 'GET') {
response.statusCode = 200;
response.end('Hello, World!\n');
} else if (url === '/health' && method === 'GET') {
response.statusCode = 200;
response.end('OK\n');
} else {
response.statusCode = 404;
response.end('Not Found\n');
}
});
server.listen(PORT, HOST, () => {
console.log(`Server running at http://${HOST}:${PORT}/`);
console.log('Press Ctrl+C to stop');
});
Run the server:
node server.js
Terminal output:
Server running at http://127.0.0.1:3000/
Press Ctrl+C to stop
Now test it. Open a second terminal and use curl:
curl http://127.0.0.1:3000/
Output:
Hello, World!
curl http://127.0.0.1:3000/health
Output:
OK
curl http://127.0.0.1:3000/missing
Output:
Not Found
Back in the first terminal, you'll see the request log:
[2025-01-15T08:32:11.042Z] GET /
[2025-01-15T08:32:14.318Z] GET /health
[2025-01-15T08:32:17.901Z] GET /missing
What's happening under the hood:
http.createServer() returns a Server object. The callback you pass is an event listener — Node registers it to fire every time an HTTP request arrives. Node's event loop keeps the process alive and calls this callback each time a new TCP connection completes an HTTP request. Without a framework, you manually check request.url and request.method to route requests.
response.end() writes the body and signals that the response is complete. Calling it is mandatory — if you don't, the client will hang waiting for more data.
Results
At this point you have:
- Node.js installed and verified
- A working understanding of the REPL for quick testing
- A runnable
.jsscript demonstrating Node's execution model - A functioning HTTP server handling three routes with proper status codes and logging
All of this with zero external dependencies.
Trade-offs
| What we did | The limitation |
Used built-in http module | URL parsing, body parsing, and routing become verbose at scale. Use Express or Fastify for real applications. |
Manual url string matching | Doesn't handle query parameters, dynamic segments, or method mismatch gracefully without extra code |
| Single file | Fine for learning; production apps need module separation, error handling middleware, and process management (e.g., PM2) |
require() syntax | Modern Node supports ES Modules (import/export). require is CommonJS — still widely used, but be aware both exist |
This setup is intentionally minimal. Its value is teaching you what's underneath — not what to ship to production.
Conclusion
You now have a concrete mental model of how Node.js works: it's a JavaScript runtime built on V8 and libuv, capable of running scripts and handling I/O (like HTTP) without a browser. The REPL is your scratchpad. node filename.js is how you execute code. The http module is the raw foundation of every Node web server.
The logical next step is to look at how Express wraps this http module — once you've seen the raw version, the abstractions will make sense instead of feeling like magic.



