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.
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 type | Content-Type set automatically | Status |
|---|---|---|
string | text/html | 200 |
Buffer | application/octet-stream | 200 |
| Plain object / Array | application/json | 200 |
Node Readable stream | application/octet-stream | 200 |
null / not set | — | 404 |
// 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 →