Core Concepts

Context

The request context object with headers, cookies, SSE, and timing.

Context

The Context object (ctx) is passed to every route handler and middleware. It wraps the native Request and provides utilities for managing state, parameters, responses, cookies, request IDs, server timing, and server-sent events.

Properties

ctx.req

The native Request object.

ctx.body

The parsed request body. If you use validation schemas, this is strongly typed. Otherwise it defaults to any (parsed JSON or Form Data).

ctx.query

URL query parameters as an object.

// GET /search?q=bklar&page=2
app.get("/search", (ctx) => {
  console.log(ctx.query.q);    // "bklar"
  console.log(ctx.query.page); // "2"
});

ctx.params

Dynamic route parameters (e.g., /users/:id).

ctx.state

Shared mutable object for passing data between middlewares and handlers.

app.use(async (ctx, next) => {
  ctx.state.user = { id: 1, role: "admin" };
  await next();
});

app.get("/me", (ctx) => ctx.json(ctx.state.user));

ctx.requestId

A unique ID for this request. Generated as UUID v4 by default, or extracted from the incoming X-Request-Id header. Included in all response headers automatically.

console.log(ctx.requestId); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"

ctx.signal

An AbortSignal that aborts when the request times out (if a route-level timeout is set) or is canceled by the client.

Response Helpers

HelperDescriptionContent-Type
ctx.json(data, status?, headers?)JSON responseapplication/json
ctx.text(data, status?, headers?)Plain text responsetext/plain
ctx.status(code, headers?)Empty response with status
ctx.download(file, filename?, headers?)File downloadauto-detected
ctx.sse()Server-Sent Events streamtext/event-stream

Every response helper automatically appends X-Request-Id and Server-Timing headers when applicable.

Cookies

// Read
const session = ctx.getCookie("session_id");

// Write
ctx.setCookie("theme", "dark", {
  httpOnly: true,
  maxAge: 3600,
  path: "/",
  secure: true,
  sameSite: "Lax",
});

Server Timing

Record timing entries that appear in the Server-Timing response header:

app.get("/users", async (ctx) => {
  const users = await ctx.time("db", () => db.findUsers());
  return ctx.json(users);
});

SSE (Server-Sent Events)

Stream events to the client:

app.get("/events", (ctx) => {
  const sse = ctx.sse();
  sse.send("message", JSON.stringify({ text: "hello" }));
  sse.close();
  return undefined;
});

See the SSE documentation for full details on server-sent events.

On this page