Streaming responses and Server-Sent Events
Zuplo's runtime is built on web-standard APIs, so streaming responses work the
same way they do in any standards-compliant JavaScript environment. You can
return a ReadableStream as a response body from a
custom handler, proxy an upstream streaming
response through the gateway unbuffered, or stream LLM tokens through Zuplo's
AI Gateway. The runtime supports the full
Streams API — ReadableStream,
WritableStream, and TransformStream — so when a handler returns a Response
whose body is a ReadableStream, Zuplo streams the bytes to the client as they
become available rather than buffering the entire response.
Return an SSE response from a custom handler
To emit Server-Sent Events from a Zuplo handler, create a ReadableStream that
writes SSE-formatted messages and return it with the text/event-stream content
type.
Code
Each SSE message ends with two newline characters (\n\n). The
text/event-stream content type tells the client to interpret the response as
an event stream.
Proxy an upstream streaming response
When your upstream API returns a streaming response — for example, an SSE
endpoint or a chunked JSON stream — you can pass it through the gateway
unbuffered. Return the upstream Response directly from your handler without
reading its body:
Code
Set UPSTREAM_API_KEY in your project's
environment variables.
Avoid reading the body
Calling .text(), .json(), or .arrayBuffer() on the upstream response
consumes the entire ReadableStream into memory. If you need to inspect the
body and return it, use .clone() first — see
Safely clone a request or response.
You can also use the built-in URL Rewrite or URL Forward handlers to proxy upstream responses. These handlers pass the response body through as a stream without buffering.
Streaming and policies
Policies in the Zuplo request pipeline interact with streaming responses differently depending on whether they read the response body:
- Policies that do not read the body — such as Set Headers or Remove Headers — pass the stream through without buffering.
- Policies that read the body — such as Replace String or XML to JSON — consume the entire response into memory before returning a new response. This effectively disables streaming for that request.
Keep streaming intact
If streaming performance is critical, place only header-modifying policies on the outbound pipeline of streaming routes. Avoid outbound policies that inspect or transform the response body.
Inbound policies run before the handler executes and do not affect response streaming. Authentication, rate limiting, and request validation all complete before the handler returns a streaming response.
Stream LLM tokens through the AI Gateway
The Zuplo AI Gateway preserves streaming behavior
from LLM providers. When you send a request with "stream": true, the gateway
proxies the provider's token-by-token response back to your application as it
arrives.
To call the AI Gateway, copy the API URL and API Key from your app's
page in the AI Gateway. Append /v1/chat/completions to the API URL and send
the app's API key as a bearer token. Name the model as providerName/model,
where providerName is the provider name configured in your gateway. See
Universal API for details.
Code
The AI Gateway applies usage limits, policies, and observability to streamed requests. Token usage and cost are tracked for each request regardless of whether streaming is enabled. See AI Gateway overview for more on usage limits and provider configuration.
Cache streaming responses
Use StreamingZoneCache to cache
ReadableStream responses across Zuplo's edge network. Split the stream with
tee() to return one copy to the client while caching the other:
Code
Caching is best suited for streams that produce a finite, repeatable result (for example, a pre-generated report). Infinite or user-specific event streams are generally not good candidates for caching.
When to use WebSockets instead
SSE is one-directional: the server pushes events to the client. If you need bidirectional communication — where the client also sends messages over the same connection — use Zuplo's WebSocket Handler instead. WebSockets support full-duplex communication and can be proxied to an upstream WebSocket server.
Next steps
- Function Handler — build custom request handlers
- Web Standard APIs — the full list of supported web APIs, including the Streams API
- StreamingZoneCache — cache streaming responses at the edge
- Safely clone a request or response
— avoid
body-usederrors when inspecting streamed bodies - AI Gateway — stream LLM tokens with cost controls and observability
- WebSocket Handler — bidirectional real-time communication