---
title: "Handling WebSockets"
description: "WebSockets enable real-time, bi-directional communication channels between a client and a server over a single TCP connection. Hono provides built-in WebSocket helper functions that abstract away r..."
last_updated: "2026-10-12T08:15:16.248386+00:00"
canonical_url: "https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/guide/how-to-guides/handling-websockets"
---

## Overview

### Introduction

WebSockets enable real-time, bi-directional communication channels between a client and a server over a single TCP connection. Hono provides built-in WebSocket helper functions that abstract away runtime-specific differences, letting you handle connection lifecycles and message events smoothly across different server environments.

> [!NOTE]
> WebSocket support depends heavily on the runtime environment hosting your Hono application. Ensure you import the `upgradeWebSocket` helper from the correct runtime-specific adapter package.

### Supported Runtimes and Adapters

Hono provides dedicated WebSocket upgrade adapters for specific JavaScript runtimes. The following table lists the supported adapters and their respective import paths:

| Runtime | Adapter Import Path |
| :--- | :--- |
| Cloudflare Workers | `hono/cloudflare-workers` |
| Deno | `hono/deno` |
| Bun | `hono/bun` |

Sources: `src/adapter/cloudflare-workers/websocket.ts`, `src/adapter/deno/websocket.ts`, `src/adapter/bun/websocket.ts`

---

## Setting Up WebSocket Routes

### Configuring the Endpoint

To establish a WebSocket connection in a Hono application, use the `upgradeWebSocket` helper within a route handler. You can define event listeners such as `onOpen`, `onMessage`, `onClose`, and `onError` to govern the behavior of the connection.

The example below demonstrates how to configure a WebSocket endpoint that echoes incoming messages back to the client:

```ts
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers' // or 'hono/deno', 'hono/bun'

const app = new Hono()

app.get(
  '/ws',
  upgradeWebSocket((c) => {
    return {
      onOpen: (event, ws) => {
        console.log('Connection opened')
      },
      onMessage: (event, ws) => {
        console.log(`Received message: ${event.data}`)
        ws.send(event.data)
      },
      onClose: (event, ws) => {
        console.log('Connection closed')
      },
      onError: (event, ws) => {
        console.error('An error occurred', event)
      },
    }
  })
)

export default app
```

> [!TIP]
> Cloudflare Workers do not natively support the `onOpen` event listener in their WebSocket implementation. If you target Cloudflare Workers, omit `onOpen` from your event definitions.

---

## Key Concepts

To effectively manage WebSockets in Hono, familiarize yourself with the following core abstractions:

* **`upgradeWebSocket`**: A middleware helper function that inspects incoming HTTP requests for upgrade headers, negotiates subprotocols, and transitions the HTTP connection into a persistent WebSocket stream.
* **`WSContext`**: A unified wrapper class providing runtime-agnostic methods and properties to interact with the active WebSocket connection. Through `WSContext`, you can send data, inspect connection states, or terminate the session.
* **`WSReadyState`**: Numeric codes representing the state of the WebSocket connection (`0` for connecting, `1` for open, `2` for closing, and `3` for closed).

---

## Controlling Connections with WSContext

The `WSContext` instance passed to every event listener provides several methods and properties to manage the socket session:

* `ws.send(data, options)`: Sends text or binary data (string, `ArrayBuffer`, or `Uint8Array`) back to the client. You can pass an optional `{ compress: true }` parameter if supported by the runtime.
* `ws.close(code, reason)`: Gracefully terminates the WebSocket connection with an optional numeric status code and text reason.
* `ws.readyState`: Returns the current numeric ready state of the socket.
* `ws.url`: Returns the `URL` object associated with the connection request.
* `ws.protocol`: Returns the negotiated subprotocol string, if any.
* `ws.raw`: Exposes the underlying runtime-specific native WebSocket object for advanced use cases.

---

## Client-Side Integration

When consuming Hono applications with the Hono RPC client (`hc`), you can establish a WebSocket connection directly from the client proxy using the `.ws()` method.

```ts
import { hc } from 'hono/client'
import type { AppType } from './server'

const client = hc<AppType>('http://localhost:8787/')

// Establish a WebSocket connection
const ws = client.ws.$ws()

ws.onopen = () => {
  ws.send('Hello from client!')
}

ws.onmessage = (event) => {
  console.log('Message from server:', event.data)
}
```

Sources: `src/client/client.ts`

> [!WARNING]
> Always verify that your reverse proxy or load balancer (such as Nginx, Cloudflare, or AWS API Gateway) is configured to permit and persist WebSocket upgrade headers (`Upgrade: websocket` and `Connection: Upgrade`), otherwise connection attempts will fail with handshake errors.

## Related

- [Streaming and SSE](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/guide/how-to-guides/streaming-and-sse)
- [Runtime Adapters](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/guide/configuration/runtime-adapters)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/llms.txt) for all pages in this wiki.
