Overview
Introduction to Streaming
Streaming allows your server to send data to clients piece-by-piece (in chunks) rather than waiting to generate the entire response all at once. This is especially useful for large payloads, real-time logs, AI text generation, or any scenario where you want to reduce Time to First Byte (TTFB) and show progress immediately.
Hono provides built-in streaming helpers that leverage web-standard ReadableStream and WritableStream objects, making them compatible with modern server runtimes like Node.js, Bun, Deno, and Cloudflare Workers.
Streaming Text and Custom Content
The stream helper gives you low-level control over a chunked text response. You can write strings or binary data to the stream progressively and close it when you are finished.
import { Hono } from 'hono'
import { stream } from 'hono/streaming'
const app = new Hono()
app.get('/stream', (c) => {
return stream(c, async (stream) => {
await stream.write('Hello ')
await stream.sleep(1000)
await stream.write('World!')
await stream.writeln(' This is a new line.')
})
})If you specifically want to stream plain text with the correct text/plain headers and safety settings, use streamText:
import { Hono } from 'hono'
import { streamText } from 'hono/streaming'
const app = new Hono()
app.get('/text', (c) => {
return streamText(c, async (stream) => {
await stream.write('Chunk 1\n')
await stream.sleep(500)
await stream.write('Chunk 2\n')
})
})Server-Sent Events (SSE)
Server-Sent Events allow a server to push real-time updates to a client over an HTTP connection using event streams (text/event-stream).
Hono provides streamSSE and the SSEStreamingApi class to simplify sending structured messages that include event names, unique IDs, retry intervals, and data payloads.
import { Hono } from 'hono'
import { streamSSE } from 'hono/streaming'
const app = new Hono()
app.get('/sse', (c) => {
let id = 0
return streamSSE(c, async (stream) => {
while (true) {
await stream.writeSSE({
data: `Server time is ${new Date().toISOString()}`,
event: 'time-update',
id: String(id++),
retry: 3000,
})
await stream.sleep(1000)
}
})
})Note
streamSSE automatically sets the required headers (Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive, and Transfer-Encoding: chunked).
Key Concepts
- Chunked Transfer Encoding: An HTTP mechanism where data is sent in a series of chunks, allowing the browser to render content before the server finishes generating the whole response.
- ReadableStream / WritableStream: Standard web APIs used underneath Hono's streaming helpers to pipe data from the server handler to the client connection.
- Server-Sent Events (SSE): A lightweight protocol for pushing text-based messages from server to client over a single long-lived HTTP connection.
Streaming API Reference
The streaming helpers pass a stream instance into your callback function. Here are the available methods on the stream objects:
| Method / Property | Description |
|---|---|
stream.write(input) | Writes a string or Uint8Array chunk to the stream. |
stream.writeln(input) | Writes a string chunk followed by a newline character. |
stream.sleep(ms) | Pauses execution for the specified number of milliseconds. |
stream.close() | Closes the stream normally. |
stream.abort() | Aborts the stream and cancels active readers. |
stream.onAbort(listener) | Registers a callback function to run if the client disconnects or aborts. |
stream.writeSSE(message) | (SSE only) Formats and sends an SSE message object. |
stream.closed | Boolean property indicating if the stream is closed. |
stream.aborted | Boolean property indicating if the stream was aborted. |
Warning
When using streamSSE, message properties (event, id, and retry) must not contain carriage return (\r) or newline (\n) characters, or Hono will throw an error.