Datastar & SSE
Stream validated HTML patches from Fast-Twitch.
Stream responses from a handler
Fast-Twitch accepts a Fetch ReadableStream as the response body. This allows a handler to send incremental updates rather than buffering the entire response.
See response-map conversion in the routing API.
Native SSE helper
Fast-Twitch now includes fast-twitch.server.sse/response for generic SSE. A producer returns an event map or a Promise of one; returning nil closes the stream. Events have string :data and optional :event, :id and nonnegative integer :retry fields.
(ns application.events
(:require [fast-twitch.server.sse :as sse]))
(defn events [_request]
(let [remaining (atom [{:event "notice" :data "one"}
{:event "notice" :data "two"}])]
(sse/response
(fn []
(let [event (first @remaining)]
(swap! remaining next)
event)))))
This state belongs to one response, so concurrent clients receive independent event sequences. The helper pulls one event when the reader requests data, sets the SSE headers and uses a zero high-water mark. Supply :on-cancel to dispose producer resources on cancellation or producer failure; also clean up resources when your producer ends normally.
Consume generic SSE with client/request! and {:transport :sse :on-event handle-event}. Fetch streaming supports an abort signal and :max-line-bytes / :max-event-bytes limits under :streaming, without automatic reconnect. Native EventSource uses client/connect! with :transport :event-source and follows the runtime's reconnect behavior. Client and transport configuration.
Add Datastar to a server-driven interface
Datastar lets HTML declare signals, event actions and requests. Its official SDK creates correctly formatted SSE messages for patching HTML elements and signals. Fast-Twitch carries the streaming response; the SDK supplies the Datastar event protocol. The framework's generic SSE helper provides event framing, while the SDK provides Datastar-specific patch operations.
Give replaceable HTML regions stable IDs. Return a full page for normal browser requests and stream patches for interactive requests. Use the same server-side templates for both paths.
Signals and actions
Declare interface state with data-signals, bind form values with data-bind, and invoke official @get or @post actions from data-on attributes. These actions manage the Datastar request and apply the server's patches.
Datastar attributes and actions describe the current browser API. Official SDK documentation describes the streaming helpers.
Handle disconnects
The original Fetch request is available under :fast-twitch.routing/request. Use its abort signal to stop work when the client disconnects. Do not continue provider calls, timers or stream writes after cancellation.
Production streaming
Return Content-Type: text/event-stream and disable response caching for the stream. Configure reverse proxies to deliver incremental chunks without buffering. Confirm this behavior on your chosen runtime and hosting platform.
Inspect the event contract
{:data "first line\nsecond line"
:event "notice"
:id "event-42"
:retry 3000}
The SSE encoder emits each data line with its own data field and a blank line after the record. Event and id fields cannot contain CR/LF; id additionally excludes NUL; retry is a nonnegative safe integer. Data must be a string, so serialize JSON payloads explicitly if the application uses JSON inside events.
next-event receives no arguments. It can wait asynchronously for business data, return an event, or return nil for EOF. The helper awaits each pull and handles framing; it does not create a scheduler, broadcast queue or persistent event log. Do not put a response cursor in a global atom. A producer failure errors its stream; on-cancel receives the reason and is called at most once through the helper's disposal guard.
Consume with Fetch or EventSource
Fetch SSE uses an HTTP request map, a required event callback and optional abort/line/event limits. The callback's Promise is awaited, so processing can apply backpressure. The consumer Promise settles at EOF or failure. Native EventSource returns a handle immediately, follows native reconnection and requires named event subscriptions for named messages. It cannot supply arbitrary headers through this wrapper. Close sources explicitly when leaving a view or finishing a job.
The complete SSE example includes both consumers, the producer, exact build commands and expected output. All option defaults and return shapes.
Generic SSE is not a Datastar patch protocol
Generic event data is whatever your application defines. Datastar patches use named protocol events and payload formatting defined by its SDK. Serving a generic event with data "hello" does not patch a DOM element. Use an installed official SDK's patch functions and the same HTML templates used for full-page responses. The framework owns Fetch response delivery; the SDK owns the patch protocol.
This documentation does not substitute a guessed SDK signature for the official SDK API. Read the version of the SDK installed in the application before choosing its adapter. Keep producer/cancellation state per response, release normal-completion resources separately, and verify that a reverse proxy delivers chunks rather than buffering them.