π¦ The http Module
http is a built-in Node.js module for building a web server β no extra install, no framework like Express required.
Think of it like a restaurant waiter: customers (browsers) place orders (requests), and the waiter (your server) brings back the right dish (a response). The http module is what lets Node.js play that role β receiving requests and sending something back.
With it, you can:
π Listen for incoming HTTP requests
π€ Respond with text, HTML, JSON, or files
π§ Handle different routes, like
/homeor/about
import { createServer } from 'node:http';π Creating a Basic Server
A minimal server that replies "Hello, World!" to every visitor.
// index.js
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.write('Hello, World!');
res.end();
});
server.listen(3000, () => {
console.log('Server is running at <http://localhost:3000>');
});createServer(callback)sets up the server. The callback runs once per incoming request, and receives two objects:reqβ the incoming request (URL, method, headers, etc.)resβ the response you build and send back
res.write(text)adds content to the response body. You can call it more than once to send content in pieces.res.end()finishes the response and sends it to the browser. Without this, the browser keeps waiting and the page never finishes loading.server.listen(3000, callback)starts the server on port3000β the callback runs once, right after the server is ready.
βΆοΈ How to Run It
Open a terminal in your project folder
Run:
node index.jsVisit
http://localhost:3000in your browserβ You'll see:
Hello, World!
Terminal output:
Server is running at <http://localhost:3000>Browser output:
Hello, World!<div class="infographic-http">
<style>
.infographic-http {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--accent2: #7ea6f2;
--line: #ddd6c9;
--ok: #1f9d55;
--ok-soft: #e5f6ec;
--radius: 10px;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
color: var(--ink);
background: transparent;
}
.infographic-http[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #13171F;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--accent2: #3d5a8f;
--line: #2c313d;
--ok: #34d399;
--ok-soft: #163227;
}
.infographic-http * { box-sizing: border-box; }
.infographic-http .h-inner { padding: 0 clamp(1rem, 4vw, 1.5rem); }
.infographic-http .h-eyebrow {
font-size: 0.7rem; font-weight: 600; letter-spacing: 0.09em;
text-transform: uppercase; color: var(--accent); margin: 0 0 0.35rem;
}
.infographic-http h2 {
font-family: 'Newsreader', Georgia, serif; font-weight: 600;
font-size: clamp(1.5rem, 4vw, 2rem); line-height: 1.15;
margin: 0 0 0.3rem; letter-spacing: -0.01em;
}
.infographic-http .h-sub { font-size: 0.9rem; color: var(--ink-soft); margin: 0 0 1.3rem; }
/* ---------- terminal ---------- */
.infographic-http .h-terminal {
border-radius: var(--radius); background: #1c1e22; border: 1px solid var(--line);
padding: 0.7rem 0.9rem; margin-bottom: 1.1rem; position: relative;
}
.infographic-http .h-term-dots { display: flex; gap: 5px; margin-bottom: 0.55rem; }
.infographic-http .h-term-dot { width: 9px; height: 9px; border-radius: 50%; background: #4b4d52; }
.infographic-http .h-term-body {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.8rem;
color: #d7dade; line-height: 1.6; min-height: 2.8em;
}
.infographic-http .h-term-body .h-prompt { color: #6ee7a0; }
.infographic-http .h-term-body .h-out { color: #9db4ff; }
.infographic-http .h-term-caret {
display: inline-block; width: 6px; height: 1em; background: #d7dade; vertical-align: text-bottom;
animation: h-blink 0.9s step-end infinite;
}
@keyframes h-blink { 50% { opacity: 0; } }
.infographic-http .h-term-replay {
position: absolute; top: 0.6rem; right: 0.7rem; background: none; border: none; cursor: pointer;
color: #7d8087; padding: 3px;
}
.infographic-http .h-term-replay svg { width: 14px; height: 14px; stroke: currentColor; }
.infographic-http .h-term-replay:hover { color: #d7dade; }
/* ---------- scene: browser <-> server ---------- */
.infographic-http .h-scene-card {
border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper-alt);
padding: 1.1rem 1.1rem 1.2rem; margin-bottom: 1rem;
}
.infographic-http .h-scene {
display: grid; grid-template-columns: 1fr 84px 1fr; align-items: center; gap: 0.4rem;
margin-bottom: 1rem;
}
@media (max-width: 560px) { .infographic-http .h-scene { grid-template-columns: 1fr; } }
.infographic-http .h-browser {
border: 1px solid var(--line); border-radius: 9px; background: var(--paper); overflow: hidden;
}
.infographic-http .h-browser-bar {
display: flex; align-items: center; gap: 0.4rem; padding: 0.4rem 0.55rem;
background: var(--paper-alt); border-bottom: 1px solid var(--line);
}
.infographic-http .h-browser-bar svg { width: 12px; height: 12px; stroke: var(--ink-soft); flex: none; }
.infographic-http .h-browser-url {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.7rem; color: var(--ink-soft);
}
.infographic-http .h-browser-body {
min-height: 64px; display: flex; align-items: center; justify-content: center;
padding: 0.8rem; font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.9rem;
font-weight: 600; color: var(--ink-soft); text-align: center;
}
.infographic-http .h-browser-body.is-filled { color: var(--accent); }
.infographic-http .h-actor {
display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
}
.infographic-http .h-actor-icon {
width: 40px; height: 40px; border-radius: 10px; background: var(--paper); border: 1px solid var(--line);
display: flex; align-items: center; justify-content: center;
box-shadow: 0 1px 3px rgba(0,0,0,0.10), 0 1px 1px rgba(0,0,0,0.06);
transition: transform 0.2s ease, border-color 0.2s ease;
}
.infographic-http[data-theme="dark"] .h-actor-icon { box-shadow: 0 1px 4px rgba(0,0,0,0.45); }
.infographic-http .h-actor-icon svg { width: 20px; height: 20px; stroke: var(--accent); }
.infographic-http .h-actor-icon.is-busy { transform: scale(1.12); border-color: var(--accent); }
.infographic-http .h-actor-label { font-size: 0.66rem; color: var(--ink-soft); font-family: 'SFMono-Regular', Consolas, Menlo, monospace; text-align: center; }
.infographic-http .h-lane {
display: flex; flex-direction: column; align-items: center; gap: 0.4rem; position: relative; height: 100%;
}
.infographic-http .h-lane-track {
width: 100%; height: 3px; background: var(--line); border-radius: 2px; position: relative; margin: 4px 0;
}
.infographic-http .h-dot {
position: absolute; top: 50%; transform: translate(-50%, -50%); left: 0;
padding: 0.15rem 0.45rem; border-radius: 999px; font-size: 0.6rem; font-weight: 700;
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; white-space: nowrap;
opacity: 0; background: var(--accent); color: #fff; transition: left 0.6s ease, opacity 0.2s ease;
}
.infographic-http .h-dot.is-go { opacity: 1; }
.infographic-http .h-dot.at-end { left: 100%; }
.infographic-http .h-dot.is-response { background: var(--ok); }
.infographic-http .h-send-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; justify-content: center; }
.infographic-http .h-msg-input {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.85rem;
padding: 0.42rem 0.65rem; border: 1px solid var(--line); border-radius: 7px;
background: var(--paper); color: var(--ink); flex: 1; min-width: 140px; max-width: 220px;
}
.infographic-http .h-msg-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.infographic-http .h-send-btn {
font: inherit; font-weight: 700; font-size: 0.8rem; color: #fff; background: var(--accent);
border: none; border-radius: 999px; padding: 0.45rem 1rem; cursor: pointer;
display: inline-flex; align-items: center; gap: 0.35rem; transition: opacity 0.15s ease;
}
.infographic-http .h-send-btn svg { width: 13px; height: 13px; stroke: #fff; }
.infographic-http .h-send-btn:disabled { opacity: 0.55; cursor: default; }
/* ---------- code strip ---------- */
.infographic-http .h-code {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.78rem; line-height: 1.85;
background: var(--paper); border: 1px solid var(--line); border-radius: 9px;
padding: 0.7rem 1rem 0.7rem 1.2rem; color: var(--ink-soft); margin-top: 1rem;
}
.infographic-http .h-code .h-line { display: block; border-radius: 4px; padding: 0 0.3rem; margin: 0 -0.3rem; transition: background 0.3s ease, color 0.3s ease; }
.infographic-http .h-code .h-line.is-hot { background: var(--accent-soft); color: var(--ink); }
.infographic-http .h-code .h-kw { color: var(--accent); font-weight: 600; }
</style>
<div class="h-inner">
<div class="h-terminal">
<button class="h-term-replay" id="htReplay" type="button" aria-label="replay">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"/><path d="M16 16h5v5"/></svg>
</button>
<div class="h-term-dots"><span class="h-term-dot"></span><span class="h-term-dot"></span><span class="h-term-dot"></span></div>
<div class="h-term-body" id="htTermBody"></div>
</div>
<div class="h-scene-card">
<div class="h-scene">
<div class="h-browser">
<div class="h-browser-bar">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<span class="h-browser-url">localhost:3000</span>
</div>
<div class="h-browser-body" id="htBrowserBody">β</div>
</div>
<div class="h-lane">
<div class="h-actor">
<span class="h-actor-icon" id="htBrowserIcon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>
</div>
<div class="h-lane-track"><span class="h-dot" id="htDotReq">GET /</span></div>
<div class="h-lane-track"><span class="h-dot is-response" id="htDotRes">200</span></div>
<div class="h-actor">
<span class="h-actor-icon" id="htServerIcon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"/><rect width="20" height="8" x="2" y="14" rx="2" ry="2"/><line x1="6" x2="6.01" y1="6" y2="6"/><line x1="6" x2="6.01" y1="18" y2="18"/></svg></span>
<span class="h-actor-label">waiter</span>
</div>
</div>
<div class="h-browser" style="display:flex; align-items:center; justify-content:center; padding:0.8rem;">
<span style="font-size:0.72rem; color:var(--ink-soft); text-align:center;">your server</span>
</div>
</div>
<div class="h-send-row">
<input class="h-msg-input" id="htMsg" type="text" value="Hello, World!" spellcheck="false" />
<button class="h-send-btn" id="htSend" type="button">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4Z"/></svg>
visit localhost:3000
</button>
</div>
<div class="h-code">
<span class="h-line" id="htLine1"><span class="h-kw">createServer</span>((req, res) => {</span>
<span class="h-line" id="htLine2"> res.<span class="h-kw">write</span>('...');</span>
<span class="h-line" id="htLine3"> res.<span class="h-kw">end</span>();</span>
<span class="h-line">});</span>
<span class="h-line" id="htLine4">server.<span class="h-kw">listen</span>(3000);</span>
</div>
</div>
</div>
<script>
(function () {
var wrapper = document.currentScript.closest('.infographic-http')
|| document.querySelector('.infographic-http');
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
var reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* ---------- terminal typing ---------- */
var termBody = wrapper.querySelector('#htTermBody');
var termTimers = [];
function clearTermTimers() { termTimers.forEach(clearTimeout); termTimers = []; }
function playTerminal(onDone) {
clearTermTimers();
termBody.innerHTML = '<span class="h-prompt">$</span> <span class="h-term-caret"></span>';
var cmd = 'node index.js';
var i = 0;
function typeCmd() {
if (i > cmd.length) {
termTimers.push(setTimeout(showOutput, 400));
return;
}
termBody.innerHTML = '<span class="h-prompt">$</span> ' + cmd.slice(0, i) + '<span class="h-term-caret"></span>';
i++;
termTimers.push(setTimeout(typeCmd, 42));
}
function showOutput() {
termBody.innerHTML = '<span class="h-prompt">$</span> ' + cmd + '<br><span class="h-out">Server is running at http://localhost:3000</span>';
if (onDone) onDone();
}
if (reduced) { showOutput(); } else { typeCmd(); }
}
termBody.innerHTML = '<span class="h-prompt">$</span> <span class="h-term-caret"></span>';
wrapper.querySelector('#htReplay').addEventListener('click', function () { playTerminal(); });
/* ---------- browser/server request-response scene ---------- */
var msgInput = wrapper.querySelector('#htMsg');
var sendBtn = wrapper.querySelector('#htSend');
var browserBody = wrapper.querySelector('#htBrowserBody');
var browserIcon = wrapper.querySelector('#htBrowserIcon');
var serverIcon = wrapper.querySelector('#htServerIcon');
var dotReq = wrapper.querySelector('#htDotReq');
var dotRes = wrapper.querySelector('#htDotRes');
var line1 = wrapper.querySelector('#htLine1');
var line2 = wrapper.querySelector('#htLine2');
var line3 = wrapper.querySelector('#htLine3');
var line4 = wrapper.querySelector('#htLine4');
var sceneTimers = [];
function clearSceneTimers() { sceneTimers.forEach(clearTimeout); sceneTimers = []; }
function setHot(el, on) { el.classList.toggle('is-hot', !!on); }
function clearHot() { [line1, line2, line3, line4].forEach(function (l) { setHot(l, false); }); }
function runCycle() {
clearSceneTimers();
sendBtn.disabled = true;
var msg = msgInput.value || '';
dotRes.textContent = msg.length > 10 ? msg.slice(0, 10) + '\u2026' : (msg || '200');
clearHot();
setHot(line4, true); // idle: listening
browserBody.classList.remove('is-filled');
browserBody.textContent = 'loading\u2026';
dotReq.classList.remove('is-go', 'at-end');
dotRes.classList.remove('is-go', 'at-end');
var t = reduced ? 0 : 50;
sceneTimers.push(setTimeout(function () {
dotReq.classList.add('is-go');
sceneTimers.push(setTimeout(function () { dotReq.classList.add('at-end'); }, 20));
}, t));
sceneTimers.push(setTimeout(function () {
serverIcon.classList.add('is-busy');
clearHot();
setHot(line1, true);
}, t + (reduced ? 0 : 650)));
sceneTimers.push(setTimeout(function () {
clearHot();
setHot(line2, true);
setHot(line3, true);
}, t + (reduced ? 0 : 1000)));
sceneTimers.push(setTimeout(function () {
serverIcon.classList.remove('is-busy');
dotReq.classList.remove('is-go', 'at-end');
dotRes.classList.add('is-go');
sceneTimers.push(setTimeout(function () { dotRes.classList.add('at-end'); }, 20));
}, t + (reduced ? 0 : 1300)));
sceneTimers.push(setTimeout(function () {
browserBody.textContent = msg || '(empty)';
browserBody.classList.add('is-filled');
dotRes.classList.remove('is-go', 'at-end');
clearHot();
setHot(line4, true);
sendBtn.disabled = false;
}, t + (reduced ? 0 : 1950)));
}
sendBtn.addEventListener('click', function () {
playTerminal();
runCycle();
});
})();
</script>
</div>