Skip to main content
doc0blade47/honodocumentation home
Sign in

Streaming and SSE

Last updated Oct 12, 2026100% grounded

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 / PropertyDescription
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.closedBoolean property indicating if the stream is closed.
stream.abortedBoolean 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.

Was this page helpful?