Create HTTP Web Server in Node.js with Code Example

โšก Smart Summary

Node.js builds a working web server in a few lines using the built-in http module. The server listens on a chosen port and answers each request with a status code and body, while separate code fetches data from other sites.

  • ๐Ÿ–ฅ๏ธ Server Creation: http.createServer registers a callback that runs once per incoming request and receives request and response objects.
  • ๐Ÿ”ข Status and Headers: writeHead sends the status code and Content-Type before any body content is written.
  • ๐Ÿ”Œ Port Binding: server.listen attaches the application to a port, and any free port number may be chosen.
  • ๐Ÿ“ฅ Outbound Requests: Fetching data from another site needs an HTTP client, and Node now ships a global fetch function.
  • โš ๏ธ Deprecated Client: The request module was deprecated in February 2020 and should not be used in new code.
  • ๐Ÿ› ๏ธ Startup Failures: An EADDRINUSE error means the chosen port is already held by another process.

Create HTTP Web Server in Node.js

The Node.js framework is mostly used to create server-based applications. It can easily be used to build web servers that serve content to users.

Several modules handle server-related requests, the built-in http module chief among them. We will look at how to create a basic web server application using Node.js, and then at how to request data from another site.

Node as a web server using HTTP

Let us look at an example of how to create and run a first Node.js application.

The application creates a simple server module that listens on port 7000. When a request is made through the browser on that port, the server sends a Hello World response to the client.

Node as a web server using HTTP

Code Explanation

  1. The require function reads a JavaScript file, executes it, and returns its exports object. Here it loads the http module so its functionality is available in the application.
  2. A server application is created from a simple function. That function runs every time a request reaches the server.
  3. When a request is received, the response is sent with a status of 200. This is the standard status code in an HTTP header for a successful response.
  4. The response body itself is the string Hello World.
  5. server.listen makes the application listen for client requests on port 7000. Any available port may be used.

If the command runs successfully, the following output appears in the browser.

Output

Node web server output

From the output:

  • Browsing to the localhost URL on port 7000 displays the string Hello World in the page.
  • Because the code specifies port 7000, the output is visible only when browsing to that port.

Here is the code for reference:

var http = require('http');

var server = http.createServer(function(request, response) {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("Hello World\n");
});

server.listen(7000);

Handling GET Requests in Node.js

Making a GET request to retrieve data from another site is straightforward in Node.js. Historically this needed the request module, installed from the command line:

npm install request

That command asks the Node package manager to download the required module and install it. When installation succeeds, the command line shows the installed module name and version in the form <name>@<version>.

npm install request output

In the snapshot above, the request module and its version number were downloaded and installed.

Making a GET request in Node.js

Code Explanation

  1. The request module installed in the previous step provides the functions needed to make GET requests to websites.
  2. A GET request is made to a site, and a callback runs once a response arrives. The callback receives three parameters:
    1. Error โ€” records any error raised while making the request.
    2. Response โ€” carries the HTTP headers returned with the response.
    3. Body โ€” contains the entire content of the response.
  3. The content received in the body parameter is written to the console.

Here is the code for reference:

var request = require("request");

request("https://example.com", function(error, response, body) {
    // Always check the error parameter before using the body
    if (error) {
        console.error("Request failed:", error.message);
        return;
    }
    console.log(body);
});

โš ๏ธ Deprecation notice: the request module was fully deprecated in February 2020 and receives no further updates. It still installs and runs, so the example above remains valid for existing projects, but npm install request now prints a deprecation warning. New code should use the built-in fetch function shown in the next section.

How to Make HTTP Requests with Native fetch in Node.js

Node has included a global fetch function since version 18, matching the API browsers already provide. No package installation is required, and the function returns a promise, so it works directly with async/await.

// No require and no npm install needed on Node 18 or later

async function getData() {
    try {
        const response = await fetch("https://example.com");

        // fetch does NOT reject on 404 or 500 โ€” check ok yourself
        if (!response.ok) {
            throw new Error("HTTP status " + response.status);
        }

        const body = await response.text();
        console.log(body);

    } catch (err) {
        // Network failures and the throw above both land here
        console.error("Request failed:", err.message);
    }
}

getData();

Three differences from the callback style are worth noting. First, fetch rejects only on a network-level failure; an HTTP 404 or 500 still resolves successfully, which is why the response.ok check exists and why omitting it is the most common mistake when moving from request. Second, the body is not delivered with the response โ€” it must be read explicitly with response.text() for plain text or response.json() for JSON, and each of those returns a promise of its own. Third, because the whole call is promise-based, a single try/catch covers both the request and the body read, replacing the error-first callback parameter entirely.

For scripts that must run on Node 16 or earlier, install node-fetch or axios instead, since both expose a comparable promise-based interface and require only a change to the import line once the runtime is upgraded.

request vs fetch vs axios: Which to Use

Three HTTP clients appear across most Node material, and only one of them is a sensible default for new work. They differ in maintenance status, in whether a dependency is needed at all, and in how each one signals an error status, so the table below sets them side by side.

Aspect request fetch (built in) axios
Status Deprecated since 2020 Maintained in core Actively maintained
Installation npm package None on Node 18+ npm package
Style Error-first callback Promise Promise
JSON parsing Manual, or a json option Manual via response.json() Automatic
Rejects on 404 or 500 No No Yes

Use fetch for new projects on a current Node version, since it adds no dependency and matches the browser API developers already know. Choose axios when automatic JSON handling, request interceptors, or rejection on error statuses would save real code. Keep request only inside legacy applications that already depend on it, and plan to replace it.

Common Node.js Server Errors and How to Fix Them

Most failures when starting a first Node server come from ports, paths, or a missing response rather than from the server code itself.

  • EADDRINUSE: another process already holds the port. Run netstat -ano | findstr :7000 on Windows, or lsof -i :7000 on macOS and Linux, then stop that process or pick a different port.
  • EACCES on a low port: ports below 1024 need elevated privileges. Use a port above 1024 during development, such as 3000 or 7000.
  • The browser hangs and never loads: the handler never called response.end(). The connection stays open until it times out, so every path through the handler must end the response.
  • Cannot find module ‘http’: the filename was misspelled, or the script is running in a browser rather than Node. Core modules need no installation.
  • Changes do not appear: Node loads the file once at startup. Restart the process after each edit, or run it under a watcher such as node --watch server.js.

FAQs

The http module is sufficient for a single endpoint. Express adds routing, middleware, and body parsing, which become worth the dependency once an application serves several routes.

Require the https module instead and pass a key and certificate to createServer. In production, a reverse proxy such as Nginx normally terminates TLS and forwards plain HTTP to Node.

Yes. AI tools convert error-first callbacks into async await reliably. Check that the generated code adds a response.ok test, because fetch resolves on 404 and that check is often omitted.

AI assistants read the error code and name the cause directly, distinguishing a port conflict from a permission problem or a syntax fault, which shortens the guesswork on a first Node project considerably.

The request object is a stream, so collect its data events into a buffer and parse the result on the end event. Express and similar frameworks provide body-parsing middleware that performs this step for you.

Summarize this post with: