Skip to main content
doc0blade47/honodocumentation home
Sign in

Handling WebSockets

Last updated Oct 12, 2026100% grounded

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:

RuntimeAdapter Import Path
Cloudflare Workershono/cloudflare-workers
Denohono/deno
Bunhono/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:

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.

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.

Was this page helpful?