Context
The Context object is passed to every route handler and middleware function. It provides access to the request, response helpers, environment bindings, and context variables.
Constructor
You typically don’t create Context instances directly. Hono creates them for each request.
const c = new Context(request, options?)
Request Properties
req
The HonoRequest instance for accessing request data.
c.req: HonoRequest<P, I['out']>
app.get('/users/:id', (c) => {
const id = c.req.param('id')
const query = c.req.query('search')
return c.json({ id, query })
})
See the HonoRequest API reference for available methods.
env
Environment bindings (e.g., Cloudflare Workers KV, D1, etc.).
app.get('/todos', async (c) => {
// Access Cloudflare D1 database
const todos = await c.env.DB.prepare('SELECT * FROM todos').all()
return c.json(todos)
})
event
The FetchEvent associated with the current request (Cloudflare Workers).
Throws an error if the context does not have a FetchEvent.
app.get('/data', async (c) => {
// Use waitUntil for async operations that shouldn't block response
c.event.waitUntil(
fetch('https://analytics.example.com/track')
)
return c.text('OK')
})
executionCtx
The ExecutionContext for the current request.
c.executionCtx: ExecutionContext
Throws an error if the context does not have an ExecutionContext.
app.get('/data', async (c) => {
c.executionCtx.waitUntil(analyticsTask())
return c.text('Processing')
})
error
Error object if a handler threw an error (available in error handlers).
c.error: Error | undefined
app.use('*', async (c, next) => {
await next()
if (c.error) {
console.error('Request error:', c.error)
}
})
finalized
Boolean indicating whether the response has been finalized.
res
The Response object for the current request.
app.use('*', async (c, next) => {
await next()
console.log('Status:', c.res.status)
})
Response Methods
text
Respond with plain text.
c.text(text, status?, headers?)
c.text(text, init?)
HTTP status code (default: 200)
Additional headers to set
Response with Content-Type: text/plain
app.get('/hello', (c) => {
return c.text('Hello, World!')
})
app.get('/error', (c) => {
return c.text('Not Found', 404)
})
json
Respond with JSON.
c.json(object, status?, headers?)
c.json(object, init?)
Object to serialize as JSON
HTTP status code (default: 200)
Additional headers to set
Response with Content-Type: application/json
app.get('/api/user', (c) => {
return c.json({ name: 'John', age: 30 })
})
app.post('/api/user', async (c) => {
const body = await c.req.json()
return c.json({ created: true }, 201)
})
html
Respond with HTML.
c.html(html, status?, headers?)
c.html(html, init?)
html
string | Promise<string>
required
HTML content to send
HTTP status code (default: 200)
Additional headers to set
return
Response | Promise<Response>
Response with Content-Type: text/html
app.get('/', (c) => {
return c.html('<h1>Hello, World!</h1>')
})
app.get('/page', (c) => {
return c.html(
<html>
<body>
<h1>Welcome</h1>
</body>
</html>
)
})
body
Respond with a raw body.
c.body(data, status?, headers?)
c.body(data, init?)
Body data (string, ArrayBuffer, ReadableStream, or Uint8Array)
Response with the provided body
app.get('/binary', (c) => {
const buffer = new Uint8Array([1, 2, 3, 4])
return c.body(buffer)
})
redirect
Redirect to a different URL.
c.redirect(location, status?)
HTTP redirect status code (default: 302)
Redirect response with Location header
app.get('/old-path', (c) => {
return c.redirect('/new-path')
})
app.get('/permanent', (c) => {
return c.redirect('/new-url', 301)
})
notFound
Return a 404 Not Found response.
app.get('/users/:id', async (c) => {
const user = await findUser(c.req.param('id'))
if (!user) {
return c.notFound()
}
return c.json(user)
})
newResponse
Create a new Response with merged headers.
c.newResponse(data, status?, headers?)
c.newResponse(data, init?)
New Response with headers merged from c.header() calls
app.get('/data', (c) => {
c.header('X-Custom', 'value')
return c.newResponse('Hello', 200)
})
Set a response header.
c.header(name, value?, options?)
Header value. If undefined, the header is deleted.
Options object with append boolean
app.get('/data', (c) => {
c.header('X-Custom', 'value')
c.header('Content-Type', 'application/json')
return c.body(JSON.stringify({ data: 'value' }))
})
// Append header
c.header('Set-Cookie', 'token=abc', { append: true })
c.header('Set-Cookie', 'user=john', { append: true })
status
Set the response status code.
app.get('/data', (c) => {
c.status(201)
return c.json({ created: true })
})
It’s usually cleaner to pass the status directly to response methods like c.json(data, 201) instead of calling c.status() separately.
Context Variables
Context variables allow you to pass data between middleware and handlers.
set
Set a context variable.
app.use('*', async (c, next) => {
c.set('requestTime', Date.now())
c.set('user', { id: 1, name: 'John' })
await next()
})
get
Get a context variable.
The stored value, or undefined if not set
app.get('/', (c) => {
const user = c.get('user')
const time = c.get('requestTime')
return c.json({ user, time })
})
var
Read-only object containing all context variables.
c.var: Readonly<ContextVariableMap & E['Variables']>
app.get('/', (c) => {
const { user, requestTime } = c.var
return c.json({ user, requestTime })
})
c.var provides type-safe access to variables when using TypeScript with proper type definitions.
Rendering Methods
render
Render content using the configured renderer.
return
Response | Promise<Response>
Rendered response
app.get('/', (c) => {
return c.render('Hello!')
})
setRenderer
Set a custom renderer for the application.
Function that renders content to a Response
app.use('*', async (c, next) => {
c.setRenderer((content) => {
return c.html(
<html>
<body>
<div>{content}</div>
</body>
</html>
)
})
await next()
})
app.get('/', (c) => c.render('Hello!'))
// Renders: <html><body><div>Hello!</div></body></html>
setLayout
Set a layout component.
Layout component function
getLayout
Get the current layout.
The current layout function, or undefined
Type Parameters
The Context class accepts generic type parameters for type safety:
Environment type defining bindings and variables
Path parameter type for type-safe param access
Input type for validated data
type Env = {
Bindings: {
DB: D1Database
}
Variables: {
user: User
}
}
app.get('/users/:id', (c: Context<Env, '/users/:id'>) => {
const id = c.req.param('id') // Type-safe
const db = c.env.DB // Type-safe
const user = c.var.user // Type-safe
return c.json({ id })
})