Building an HTTP Server

· 3 min read · Updated March 7, 2026 · beginner
http server node beginner request response

Node.js was built with server-side JavaScript in mind, and its built-in http module makes creating web servers straightforward. In this tutorial, you’ll build HTTP servers from scratch, handle different routes, and process client requests.

Your First HTTP Server

The http module provides everything you need to create a server. Here’s a minimal example:

import { createServer } from 'http';

const server = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, World!');
});

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

Run this with node server.js and visit http://localhost:3000 in your browser. The server responds with “Hello, World!” for every request.

The callback function receives two objects:

  • req (request) — contains details about the incoming request
  • res (response) — lets you send data back to the client

Understanding the Request Object

The req object contains all the information about what the client asked for:

import { createServer } from 'http';

const server = createServer((req, res) => {
  console.log('Method:', req.method);    // GET, POST, PUT, DELETE
  console.log('URL:', req.url);          // The path requested
  console.log('Headers:', req.headers);  // All request headers
  
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Request received');
});

server.listen(3000);

Common req properties:

  • req.method — HTTP verb (GET, POST, etc.)
  • req.url — The path and query string
  • req.headers — Object containing all headers

Handling Different Routes

Most applications need to handle multiple routes. Here’s how to do it:

import { createServer } from 'http';

const server = createServer((req, res) => {
  const pathname = req.url.split('?')[0];
  
  if (pathname === '/' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>Welcome Home</h1>');
  } 
  else if (pathname === '/about' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>About Us</h1>');
  } 
  else if (pathname === '/api/users' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ users: [] }));
  } 
  else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found');
  }
});

server.listen(3000);

This handles three routes plus a 404 fallback.

Reading Request Body Data

For POST and PUT requests, you need to read the request body:

import { createServer } from 'http';

const server = createServer(async (req, res) => {
  if (req.method === 'POST' && req.url === '/submit') {
    // Collect chunks of data
    const chunks = [];
    for await (const chunk of req) {
      chunks.push(chunk);
    }
    const body = JSON.parse(Buffer.concat(chunks).toString());
    
    console.log('Received:', body);
    
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ success: true, received: body }));
  } else {
    res.writeHead(404);
    res.end();
  }
});

server.listen(3000);

Test it with curl:

curl -X POST http://localhost:3000/submit \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "age": 30}'

Setting Response Headers

Proper headers are essential for correct behavior:

import { createServer } from 'http';

const server = createServer((req, res) => {
  // JSON response
  if (req.url === '/api/data') {
    res.writeHead(200, {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    });
    res.end(JSON.stringify({ message: 'Here is your data' }));
  }
  
  // HTML with custom headers
  else if (req.url === '/') {
    res.writeHead(200, {
      'Content-Type': 'text/html',
      'Cache-Control': 'no-cache'
    });
    res.end('<html><body><h1>Hello!</h1></body></html>');
  }
  
  // Redirect
  else if (req.url === '/old-page') {
    res.writeHead(301, { 'Location': '/new-page' });
    res.end();
  }
  
  else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

server.listen(3000);

Working with HTTPS

For secure servers, use the https module with SSL certificates:

import { createServer } from 'https';
import { readFileSync } from 'fs';

const options = {
  key: readFileSync('private-key.pem'),
  cert: readFileSync('certificate.pem')
};

const server = createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Secure connection established');
});

server.listen(443, () => {
  console.log('HTTPS server running on port 443');
});

Summary

You’ve learned how to:

  • Create a basic HTTP server with createServer()
  • Access request method, URL, and headers
  • Handle different routes with conditional logic
  • Read POST request bodies
  • Set response headers for JSON, HTML, and redirects
  • Set up HTTPS for secure connections

The http module is powerful enough for many applications, but for production use, frameworks like Express provide nicer APIs and more features.