Node.js
HTTP module
response handling
server response
web development

How to return response from http module in Node.js?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

With Node's built-in http module, you do not "return" an HTTP response value the way you might in a framework route handler. Instead, you write to the ServerResponse object and finish the response with res.end().

The Minimal Correct Response

This is the basic pattern:

javascript
1const http = require('http');
2
3const server = http.createServer((req, res) => {
4  res.statusCode = 200;
5  res.setHeader('Content-Type', 'application/json');
6  res.end(JSON.stringify({ ok: true }));
7});
8
9server.listen(3000);

res.end(...) is what actually completes the response. Without it, the client may wait indefinitely for the stream to finish.

Route By Checking URL And Method

In raw http, you branch manually:

javascript
1const server = http.createServer((req, res) => {
2  if (req.method === 'GET' && req.url === '/health') {
3    res.writeHead(200, { 'Content-Type': 'text/plain' });
4    return res.end('healthy');
5  }
6
7  res.writeHead(404, { 'Content-Type': 'application/json' });
8  res.end(JSON.stringify({ error: 'Not found' }));
9});

The return res.end(...) style is useful because it prevents accidental extra writes later in the handler.

That is often what people really mean when they ask how to "return" a response.

Handle Request Bodies Asynchronously

If the response depends on the request body, you must wait for the body stream to finish:

javascript
1const server = http.createServer((req, res) => {
2  if (req.method === 'POST' && req.url === '/echo') {
3    let body = '';
4
5    req.on('data', chunk => {
6      body += chunk;
7    });
8
9    req.on('end', () => {
10      res.writeHead(200, { 'Content-Type': 'application/json' });
11      res.end(JSON.stringify({ received: body }));
12    });
13
14    return;
15  }
16
17  res.writeHead(404);
18  res.end();
19});

You cannot meaningfully respond with parsed body data before the end event has fired.

Return Errors Explicitly Too

Raw http does not add error handling for you. If JSON parsing can fail, send a clear response:

javascript
1req.on('end', () => {
2  try {
3    const parsed = JSON.parse(body);
4    res.writeHead(200, { 'Content-Type': 'application/json' });
5    res.end(JSON.stringify(parsed));
6  } catch {
7    res.writeHead(400, { 'Content-Type': 'application/json' });
8    res.end(JSON.stringify({ error: 'Invalid JSON' }));
9  }
10});

Every request path should eventually send exactly one complete response.

That is the core discipline when using the low-level http module directly.

If you need to stream partial output, you can use res.write(...) one or more times before the final res.end(). The same rule still applies: the response is not complete until end() is called, and headers generally need to be settled before the body starts streaming.

return Is About Control Flow, Not HTTP Semantics

This is the subtle but important distinction:

  • 'return exits your JavaScript function'
  • 'res.end() finishes the HTTP response'

Often you use both:

javascript
return res.end('done');

But only res.end() matters to the client. The return is for your handler's internal control flow.

This distinction becomes especially important when code branches through several callbacks or asynchronous operations. A clean early return after res.end() helps prevent accidental double responses.

That is a common raw-HTTP bug.

Common Pitfalls

One common mistake is returning a plain object from the handler and expecting Node's http server to serialize it automatically.

Another issue is forgetting res.end(), which leaves the connection open.

A third problem is calling res.end() twice on the same request path.

Finally, when the response depends on asynchronous work, developers sometimes try to respond too early instead of waiting for the callback or event where the data actually becomes available.

Summary

  • In Node's raw http module, send responses by writing to res and calling res.end().
  • Use writeHead or setHeader to control status and headers.
  • Branch manually on req.method and req.url.
  • Wait for asynchronous body parsing or other async work before ending the response.
  • 'return helps your JavaScript control flow, but res.end() is what actually returns the HTTP response.'
  • Send exactly one response per request path and keep that rule explicit.

Course illustration
Course illustration

All Rights Reserved.