The Response Object

ctx.response Controls Body, Status, Headers, and Redirects

The Response Object

ctx.response exposes ctx.body, ctx.status, ctx.type, ctx.set, ctx.redirect, and ctx.attachment — everything you need to build any HTTP response.

4 min read Level 1/5 #koa#response#ctx.response
What you'll learn
  • Set the response body to a string, object, Buffer, or readable stream
  • Control status codes and Content-Type with ctx.status and ctx.type
  • Add custom headers, redirect clients, and trigger file downloads

ctx.response is Koa’s wrapper around Node’s ServerResponse. The properties you write to here become the HTTP response sent to the client.

ctx.body — The Response Body

Koa adapts its behaviour based on what type you assign to ctx.body:

Value typeContent-Type set automaticallyStatus
stringtext/html200
Bufferapplication/octet-stream200
Plain object / Arrayapplication/json200
Node Readable streamapplication/octet-stream200
null / not set404
// String
ctx.body = "Hello!";

// JSON (Koa serialises the object automatically)
ctx.body = { user: "ada", role: "admin" };

// Stream (e.g., a file)
import fs from "node:fs";
ctx.body = fs.createReadStream("./report.pdf");

ctx.status — HTTP Status Code

app.use(async (ctx) => {
  ctx.status = 201;
  ctx.body = { id: 42 };
});

If you set only ctx.status and not ctx.body, Koa will use the status text as the body (e.g., "Not Found" for 404).

ctx.type — Content-Type Shorthand

ctx.type = "json";           // application/json; charset=utf-8
ctx.type = "text/plain";
ctx.type = "html";

ctx.set — Set Response Headers

// Single header
ctx.set("X-Request-Id", "abc-123");

// Multiple at once
ctx.set({
  "Cache-Control": "no-store",
  "X-Powered-By": "Koa",
});

ctx.redirect — HTTP Redirects

app.use(async (ctx) => {
  ctx.redirect("https://jsschools.com"); // 302 by default
});

// Permanent redirect
app.use(async (ctx) => {
  ctx.status = 301;
  ctx.redirect("/new-path");
});

ctx.attachment — File Downloads

ctx.attachment(filename) sets the Content-Disposition header so the browser prompts a download instead of displaying the content:

import fs from "node:fs";

app.use(async (ctx) => {
  ctx.attachment("report.csv");
  ctx.body = fs.createReadStream("./data/report.csv");
});

Up Next

Now that you can read requests and write responses, learn how Koa middleware ties everything together.

Middleware Introduction →