Menu

Node.js HTTP Server: http.createServer With Examples

http.createServer() takes one function that runs for every request with req and res. You read the method and URL from req, then set a status, headers and a body on res and call res.end().

This page includes runnable editors. Edit, run, and see output instantly.

http.createServer() creates a web server from one function, the request handler, which Node calls for every incoming request with two objects: req (the method, URL and headers the client sent) and res (what you send back). Set a status code and headers on res, then call res.end() with the body. server.listen(3000) starts accepting connections on port 3000.

The first request answers You asked for GET /hello?name=Ada, and the Console logs the same method and URL. Send DELETE /anything from the request bar: the same handler answers it, because a plain http server has no routes. Every request goes through the one function.

Send JSON and set the status code

res.writeHead(status, headers) sets the status code and headers in one call. For JSON, set Content-Type: application/json and send the result of JSON.stringify(); res.end() only accepts a string or a Buffer.

GET /users?limit=1 returns [{"id":1,"name":"Ada"}]. req.url is the path plus the query string, so new URL(req.url, 'http://localhost') splits it into pathname and searchParams (the base is only there because URL needs an absolute address). Send GET /nothing and the status turns to 404.

Route requests with a switch

A small API needs nothing more than a switch on the method and path. Build a key such as 'GET /users' and give each route its own case:

Send POST /users with the body {"name": "Grace"}: the answer is 201 with {"id":2,"name":"Grace"}, and GET /users now lists both users. Send the same POST with the body hello and you get 400 with {"error":"Body must be JSON"}.

Read a POST body

Node does not parse the body for you. req is a readable stream, and the body arrives in chunks through data events, then end fires once it is complete. readBody() above collects the chunks into a string and returns a promise, so the handler can await it. Since req is async iterable, this loop does the same job:

let data = '';
for await (const chunk of req) data += chunk;
const body = JSON.parse(data);

A real server also limits the size (stop reading and answer 413 once data.length passes a limit) and checks req.headers['content-type'] before calling JSON.parse.

Common mistakes

Forgetting res.end(). A branch that sets a status but never ends the response leaves the client waiting until it times out.

Setting a header after the body. Once res.end() or the first res.write() has run, the headers are sent, and res.setHeader() throws ERR_HTTP_HEADERS_SENT. Use return when you send a response early, as the examples do.

Comparing req.url with a path. req.url includes the query string, so req.url === '/users' is false for /users?limit=1. Compare pathname.

When to use Express instead

The http module is enough for a health check, a webhook receiver or learning how HTTP works. Once you need route parameters like /users/:id, JSON body parsing, middleware and error handling, you end up writing your own small framework. Express is that framework, built on the same req and res objects; Express routing shows the same API with app.get() and app.post().

Frequently Asked Questions

What is the difference between res.write and res.end?

res.write() sends a chunk of the body and keeps the response open, so you can call it many times. res.end() sends an optional last chunk and finishes the response. Every response needs exactly one res.end().

How do I stop a Node HTTP server?

Call server.close(). It stops accepting new connections at once and runs its callback when the open ones have finished, which is what a clean shutdown on SIGTERM needs.

How do I use HTTPS with the http module?

Use the https module instead: https.createServer({ key, cert }, handler) takes the same handler plus a private key and a certificate. In production a proxy such as Nginx or a hosting platform usually terminates TLS, and your Node server keeps listening on plain HTTP.

What port should a Node server listen on?

Any free port above 1024 works without admin rights; 3000 and 8080 are common in development. Hosting platforms usually tell you the port in an environment variable, so write server.listen(process.env.PORT || 3000).

Coddy programming languages illustration

Learn to code with Coddy

Get started