> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# Context

> Learn about the Context object in Hono, including accessing request and response data, context variables, and helper methods.

## Overview

The Context object (`c`) is passed to every handler and middleware function. It provides access to the request, response, environment variables, and utility methods for building responses.

From `src/context.ts:293-299`:

```typescript theme={null}
export class Context<
  E extends Env = any,
  P extends string = any,
  I extends Input = {},
> {
  // Context implementation
}
```

## Request Access

Access the request object through `c.req`:

```typescript theme={null}
app.get('/users/:id', (c) => {
  // Get path parameters
  const id = c.req.param('id')
  const params = c.req.param() // All params

  // Get query parameters
  const search = c.req.query('search')
  const queries = c.req.queries() // All queries

  // Get headers
  const auth = c.req.header('Authorization')
  const headers = c.req.header() // All headers

  // Get request method and path
  const method = c.req.method
  const path = c.req.path
  const url = c.req.url

  return c.json({ id, search, auth, method, path })
})
```

From `src/context.ts:364-369`:

```typescript theme={null}
/**
 * `.req` is the instance of {@link HonoRequest}.
 */
get req(): HonoRequest<P, I['out']> {
  this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult)
  return this.#req
}
```

## Response Methods

The Context provides several methods for returning responses:

### Text Response

Return plain text:

```typescript theme={null}
app.get('/hello', (c) => {
  return c.text('Hello, World!')
})

app.get('/custom', (c) => {
  return c.text('Created', 201)
})
```

From `src/context.ts:670-694`:

<CodeGroup>
  ```typescript Text Method theme={null}
  text: TextRespond = (
    text: string,
    arg?: ContentfulStatusCode | ResponseOrInit,
    headers?: HeaderRecord
  ): ReturnType<TextRespond> => {
    return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized
      ? (new Response(text) as ReturnType<TextRespond>)
      : (this.#newResponse(
          text,
          arg,
          setDefaultContentType(TEXT_PLAIN, headers)
        ) as ReturnType<TextRespond>)
  }
  ```
</CodeGroup>

### JSON Response

Return JSON data:

```typescript theme={null}
app.get('/api/users', (c) => {
  return c.json({
    users: [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ]
  })
})

app.post('/api/users', async (c) => {
  const user = await c.req.json()
  return c.json({ created: user }, 201)
})
```

From `src/context.ts:696-721`:

<CodeGroup>
  ```typescript JSON Method theme={null}
  json: JSONRespond = <
    T extends JSONValue | {} | InvalidJSONValue,
    U extends ContentfulStatusCode = ContentfulStatusCode,
  >(
    object: T,
    arg?: U | ResponseOrInit<U>,
    headers?: HeaderRecord
  ): JSONRespondReturn<T, U> => {
    return this.#newResponse(
      JSON.stringify(object),
      arg,
      setDefaultContentType('application/json', headers)
    ) as any
  }
  ```
</CodeGroup>

### HTML Response

Return HTML content:

```typescript theme={null}
app.get('/', (c) => {
  return c.html('<h1>Hello Hono!</h1>')
})

app.get('/page', (c) => {
  return c.html(`
    <!DOCTYPE html>
    <html>
      <head><title>My Page</title></head>
      <body><h1>Welcome</h1></body>
    </html>
  `)
})
```

From `src/context.ts:723-733`:

```typescript theme={null}
html: HTMLRespond = (
  html: string | Promise<string>,
  arg?: ContentfulStatusCode | ResponseOrInit<ContentfulStatusCode>,
  headers?: HeaderRecord
): Response | Promise<Response> => {
  const res = (html: string) =>
    this.#newResponse(html, arg, setDefaultContentType('text/html; charset=UTF-8', headers))
  return typeof html === 'object'
    ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res)
    : res(html)
}
```

### Redirect

Redirect to another URL:

```typescript theme={null}
app.get('/old-path', (c) => {
  return c.redirect('/new-path')
})

app.get('/external', (c) => {
  return c.redirect('https://example.com', 301)
})
```

From `src/context.ts:735-762`:

<CodeGroup>
  ```typescript Redirect Method theme={null}
  redirect = <T extends RedirectStatusCode = 302>(
    location: string | URL,
    status?: T
  ): Response & TypedResponse<undefined, T, 'redirect'> => {
    const locationString = String(location)
    this.header(
      'Location',
      !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString)
    )
    return this.newResponse(null, status ?? 302) as any
  }
  ```
</CodeGroup>

### Body Response

Return raw body data:

```typescript theme={null}
app.get('/file', (c) => {
  const data = new Uint8Array([1, 2, 3])
  return c.body(data)
})

app.get('/stream', (c) => {
  const stream = new ReadableStream({
    start(controller) {
      controller.enqueue('chunk 1')
      controller.enqueue('chunk 2')
      controller.close()
    }
  })
  return c.body(stream)
})
```

From `src/context.ts:643-668`:

```typescript theme={null}
body: BodyRespond = (
  data: Data | null,
  arg?: StatusCode | RequestInit,
  headers?: HeaderRecord
): ReturnType<BodyRespond> => this.#newResponse(data, arg, headers) as ReturnType<BodyRespond>
```

## Headers

### Setting Headers

```typescript theme={null}
app.get('/api/data', (c) => {
  c.header('X-Custom-Header', 'value')
  c.header('Cache-Control', 'no-cache')
  return c.json({ data: 'example' })
})
```

From `src/context.ts:500-527`:

<CodeGroup>
  ```typescript Header Method theme={null}
  header: SetHeaders = (name, value, options): void => {
    if (this.finalized) {
      this.#res = createResponseInstance((this.#res as Response).body, this.#res)
    }
    const headers = this.#res ? this.#res.headers : (this.#preparedHeaders ??= new Headers())
    if (value === undefined) {
      headers.delete(name)
    } else if (options?.append) {
      headers.append(name, value)
    } else {
      headers.set(name, value)
    }
  }
  ```
</CodeGroup>

### Appending Headers

```typescript theme={null}
app.get('/multi-header', (c) => {
  c.header('Set-Cookie', 'session=abc', { append: true })
  c.header('Set-Cookie', 'token=xyz', { append: true })
  return c.text('Headers set')
})
```

## Status Code

Set HTTP status code:

```typescript theme={null}
app.post('/api/users', async (c) => {
  c.status(201)
  return c.json({ message: 'User created' })
})

app.delete('/api/users/:id', (c) => {
  c.status(204)
  return c.body(null)
})
```

From `src/context.ts:529-531`:

```typescript theme={null}
status = (status: StatusCode): void => {
  this.#status = status
}
```

## Context Variables

Store and retrieve values during request processing:

### Setting Variables

```typescript theme={null}
app.use('*', async (c, next) => {
  c.set('requestId', crypto.randomUUID())
  c.set('startTime', Date.now())
  await next()
})
```

From `src/context.ts:533-556`:

<CodeGroup>
  ```typescript Set Method theme={null}
  set: Set<
    IsAny<E> extends true
      ? {
          Variables: ContextVariableMap & Record<string, any>
        }
      : E
  > = (key: string, value: unknown) => {
    this.#var ??= new Map()
    this.#var.set(key, value)
  }
  ```
</CodeGroup>

### Getting Variables

```typescript theme={null}
app.get('/profile', (c) => {
  const requestId = c.get('requestId')
  const user = c.get('user')
  return c.json({ requestId, user })
})
```

From `src/context.ts:558-580`:

```typescript theme={null}
get: Get<
  IsAny<E> extends true
    ? {
        Variables: ContextVariableMap & Record<string, any>
      }
    : E
> = (key: string) => {
  return this.#var ? this.#var.get(key) : undefined
}
```

### Accessing Variables with `.var`

Read-only access to all variables:

```typescript theme={null}
app.get('/info', (c) => {
  const vars = c.var
  // Access all context variables as object
  return c.json(vars)
})
```

From `src/context.ts:582-602`:

```typescript theme={null}
get var(): Readonly<
  ContextVariableMap & (IsAny<E['Variables']> extends true ? Record<string, any> : E['Variables'])
> {
  if (!this.#var) {
    return {} as any
  }
  return Object.fromEntries(this.#var)
}
```

## Type-Safe Variables

Define variable types for type safety:

```typescript theme={null}
type Env = {
  Variables: {
    user: { id: string; email: string }
    requestId: string
  }
}

const app = new Hono<Env>()

app.use('*', async (c, next) => {
  c.set('requestId', crypto.randomUUID())
  c.set('user', { id: '123', email: 'user@example.com' })
  await next()
})

app.get('/profile', (c) => {
  const user = c.get('user') // Type: { id: string; email: string }
  const requestId = c.get('requestId') // Type: string
  return c.json({ user, requestId })
})
```

## Environment Variables

Access environment bindings (Cloudflare Workers, etc.):

```typescript theme={null}
type Env = {
  Bindings: {
    DB: D1Database
    BUCKET: R2Bucket
    API_KEY: string
  }
}

const app = new Hono<Env>()

app.get('/data', async (c) => {
  const db = c.env.DB
  const bucket = c.env.BUCKET
  const apiKey = c.env.API_KEY

  const result = await db.prepare('SELECT * FROM users').all()
  return c.json(result)
})
```

From `src/context.ts:302-315`:

<CodeGroup>
  ````typescript Environment Property theme={null}
  /**
   * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers.
   *
   * @example
   * ```ts
   * // Environment object for Cloudflare Workers
   * app.get('*', async c => {
   *   const counter = c.env.COUNTER
   * })
   * ```
   */
  env: E['Bindings'] = {}
  ````
</CodeGroup>

## Execution Context

Access the execution context (for Cloudflare Workers):

```typescript theme={null}
app.get('/task', async (c) => {
  // Schedule background task
  c.executionCtx.waitUntil(
    fetch('https://api.example.com/log', {
      method: 'POST',
      body: JSON.stringify({ request: c.req.path })
    })
  )

  return c.text('Task scheduled')
})
```

From `src/context.ts:385-397`:

<CodeGroup>
  ```typescript ExecutionContext Property theme={null}
  get executionCtx(): ExecutionContext {
    if (this.#executionCtx) {
      return this.#executionCtx as ExecutionContext
    } else {
      throw Error('This context has no ExecutionContext')
    }
  }
  ```
</CodeGroup>

From `src/context.ts:29-52`:

```typescript theme={null}
export interface ExecutionContext {
  /**
   * Extends the lifetime of the event callback until the promise is settled.
   */
  waitUntil(promise: Promise<unknown>): void
  /**
   * Allows the event to be passed through to subsequent event listeners.
   */
  passThroughOnException(): void
}
```

## Rendering

### Custom Renderer

Set a custom renderer for templating:

```typescript theme={null}
import { html } from 'hono/html'

app.use('*', async (c, next) => {
  c.setRenderer((content, props) => {
    return c.html(html`
      <!DOCTYPE html>
      <html>
        <head><title>${props?.title || 'My App'}</title></head>
        <body>
          <header><h1>${props?.title}</h1></header>
          <main>${content}</main>
        </body>
      </html>
    `)
  })
  await next()
})

app.get('/', (c) => {
  return c.render('Welcome to Hono!', { title: 'Home' })
})
```

From `src/context.ts:437-497`:

<CodeGroup>
  ```typescript Render & SetRenderer theme={null}
  render: Renderer = (...args) => {
    this.#renderer ??= (content: string | Promise<string>) => this.html(content)
    return this.#renderer(...args)
  }

  setRenderer = (renderer: Renderer): void => {
    this.#renderer = renderer
  }
  ```
</CodeGroup>

## Error Property

Access errors thrown in middleware:

```typescript theme={null}
app.use('*', async (c, next) => {
  await next()
  
  if (c.error) {
    console.error('Error occurred:', c.error)
  }
})
```

From `src/context.ts:317-333`:

<CodeGroup>
  ````typescript Error Property theme={null}
  /**
   * `.error` can get the error object from the middleware if the Handler throws an error.
   *
   * @example
   * ```ts
   * app.use('*', async (c, next) => {
   *   await next()
   *   if (c.error) {
   *     // do something...
   *   }
   * })
   * ```
   */
  error: Error | undefined
  ````
</CodeGroup>

## Response Access

Access or set the response:

```typescript theme={null}
app.use('*', async (c, next) => {
  await next()
  
  // Access response
  console.log(c.res.status)
  console.log(c.res.headers)
})
```

From `src/context.ts:399-434`:

<CodeGroup>
  ```typescript Response Property theme={null}
  get res(): Response {
    return (this.#res ||= createResponseInstance(null, {
      headers: (this.#preparedHeaders ??= new Headers()),
    }))
  }

  set res(_res: Response | undefined) {
    if (this.#res && _res) {
      _res = createResponseInstance(_res.body, _res)
      for (const [k, v] of this.#res.headers.entries()) {
        if (k === 'content-type') {
          continue
        }
        if (k === 'set-cookie') {
          const cookies = this.#res.headers.getSetCookie()
          _res.headers.delete('set-cookie')
          for (const cookie of cookies) {
            _res.headers.append('set-cookie', cookie)
          }
        } else {
          _res.headers.set(k, v)
        }
      }
    }
    this.#res = _res
    this.finalized = true
  }
  ```
</CodeGroup>

## Not Found Handler

Trigger the not found handler:

```typescript theme={null}
app.get('/users/:id', async (c) => {
  const user = await findUser(c.req.param('id'))
  
  if (!user) {
    return c.notFound()
  }
  
  return c.json(user)
})
```

From `src/context.ts:764-779`:

```typescript theme={null}
notFound = (): ReturnType<NotFoundHandler> => {
  this.#notFoundHandler ??= () => createResponseInstance()
  return this.#notFoundHandler(this)
}
```

## Best Practices

<Tip>
  * Use TypeScript to define environment and variable types
  * Set context variables in middleware for cross-handler data sharing
  * Use appropriate response methods (`json`, `text`, `html`) for content types
  * Access `c.req` for all request data instead of the raw request object
  * Leverage `c.executionCtx` for background tasks in Cloudflare Workers
</Tip>

<Warning>
  Don't modify the raw request object. Use Context methods and properties for all request/response operations.
</Warning>

## Related

* [Handlers](/concepts/handlers) - Learn about request handlers
* [Middleware](/concepts/middleware) - Use middleware to modify context
* [Validation](/concepts/validation) - Validate and transform request data
