Sending Responses

1. Sending Text Response

InputBehavior
StringContent-Type: text/html
Object/ArrayCalls res.json() internally
BufferContent-Type: application/octet-stream
null/undefinedEmpty body

Example: res.send variants

res.send("<h1>Hello</h1>");           // text/html
res.send({ ok: true });                  // application/json
res.send(Buffer.from("binary"));         // octet-stream
res.type("text/plain").send("plain");

2. Sending JSON Response

APIDetail
res.json(obj)JSON body, Content-Type set
res.jsonp(obj)JSONP wrapped in callback
Setting json spacesPretty-print indentation
Setting json replacerJSON.stringify replacer fn

Example: JSON with status

res.status(201).json({ id, createdAt: new Date().toISOString() });

3. Setting Response Status

CodeMeaning
200 OKDefault success
201 CreatedPOST successful, resource created
204 No ContentSuccess, no body (DELETE)
301/302Redirect (permanent / temporary)
304 Not ModifiedCached resource
400 Bad RequestValidation failure
401 UnauthorizedMissing/invalid auth
403 ForbiddenAuthenticated but not allowed
404 Not FoundResource missing
409 ConflictDuplicate / version mismatch
422 UnprocessableSemantic validation
429 Too Many RequestsRate-limited
500/502/503Server errors

4. Chaining Status and Response

Example: Fluent chain

return res.status(404).json({ error: "Not found" });
return res.status(204).end();
return res.status(303).location("/login").end();

5. Redirecting Requests

Example: Redirect variants

res.redirect("/login");                  // 302 default
res.redirect(301, "/new-url");           // permanent
res.redirect("back");                    // Referer header or "/"
res.redirect(303, "/orders/" + id);      // POST→GET pattern
StatusUse
301 Moved PermanentlySEO-safe permanent URL change
302 FoundTemporary (default)
303 See OtherPOST/PUT → GET (PRG pattern)
307/308Method-preserving redirects

6. Rendering Views

Example: Template rendering

res.render("user-profile", { user, csrfToken: req.csrfToken() }, (err, html) => {
  if (err) return next(err);
  res.send(html);
});
ArgumentPurpose
viewTemplate path relative to views dir
localsData merged with app.locals + res.locals
callbackOptional (err, html) handler

7. Sending Files

OptionDefaultPurpose
rootRequired if path is relative
maxAge0Cache-Control max-age
headersCustom headers map
dotfilesignoreHidden file behavior
acceptRangestrueHTTP range requests

Example: Send + handle errors

res.sendFile("invoice.pdf", { root: "private" }, (err) => {
  if (err) next(err.status === 404 ? new HttpError(404) : err);
});

8. Downloading Files

Example: Forced download with custom name

res.download("/private/report.pdf", `report-${date}.pdf`, {
  headers: { "X-Doc-Id": id }
});
APIEffect
res.download(path, filename?, opts?, cb?)Sets Content-Disposition: attachment
res.attachment(filename?)Just sets disposition header (use with send)

9. Setting Response Headers

Example: Header API

res.set("X-Frame-Options", "DENY");
res.set({ "X-Custom": "1", "X-Trace": req.id });
res.header("Cache-Control", "no-store");
APIDescription
res.set(name, value)Set single header
res.set(obj)Set multiple
res.header()Alias of set
res.get(name)Read response header
res.removeHeader(name)Remove (Node API)

10. Setting Content Type

Example: res.type()

res.type("json");          // application/json
res.type("html");          // text/html
res.type(".png");          // image/png
res.type("application/xml");

11. Appending Headers

res.append("Set-Cookie", "lang=en; Path=/");
res.append("Set-Cookie", "theme=dark; Path=/");
res.append("Vary", "Accept-Encoding");
set vs appendBehavior
res.setReplaces existing value
res.appendAdds another value (array)

12. Sending Status-Only Response

APIEquivalent
res.sendStatus(204)res.status(204).send("No Content")
res.sendStatus(404)res.status(404).send("Not Found")

13. Ending Response

Example: Manual end (streaming)

res.writeHead(200, { "Content-Type": "text/plain" });
res.write("chunk 1\n");
res.write("chunk 2\n");
res.end();  // Mandatory — closes the response stream
Warning: Calling any response method twice (e.g., res.json() after res.send()) throws ERR_HTTP_HEADERS_SENT.