Skip to main content
Streaming allows your application to send content to the browser progressively as it becomes ready, rather than waiting for the entire page to render. This dramatically improves perceived performance and time-to-interactive.

Why Streaming?

Traditional SSR waits for the entire page to render before sending any content:
With streaming, the browser receives and displays content as it renders:
Benefits:
  • Faster First Contentful Paint (FCP)
  • Better Time to Interactive (TTI)
  • Improved perceived performance
  • Better user experience on slow connections

Enabling Streaming

Use the defaultStreamHandler instead of defaultRenderHandler:
app/server.ts
Compare with non-streaming (string rendering):

How Streaming Works

TanStack Start uses React’s streaming SSR capabilities:

1. Initial HTML Shell

The server immediately sends the HTML shell:
The browser can parse and display this immediately, showing layout and loading states.

2. Component Streaming

As components render, their HTML streams to the browser:

3. Suspense Boundaries

React Suspense enables selective streaming:
Flow:
  1. Server sends <h1>Dashboard</h1> immediately
  2. Server sends both <div>Loading stats...</div> and <div>Loading activity...</div>
  3. When Stats data loads, server sends <Stats /> HTML and inline script to replace fallback
  4. When Activity data loads, server sends <Activity /> HTML and inline script to replace fallback

4. Hydration After Streaming

After HTML arrives, React hydrates the page:
app/client.tsx
The client:
  1. Reads serialized state from the HTML
  2. Attaches event listeners
  3. Makes the page fully interactive

Streaming Server Functions

Server functions can also stream responses:

Async Generators

Use generator functions to stream data:

ReadableStream

Return a ReadableStream for binary data streaming:

Frame Protocol

For advanced streaming scenarios, TanStack Start uses a binary frame protocol to multiplex JSON and raw streams:

Protocol Format

Each frame has a header:
Frame types:
  • 0 - JSON data (streamId 0)
  • 1 - Raw stream chunk (streamId > 0)
  • 2 - Stream end (streamId > 0)
  • 3 - Stream error (streamId > 0)

Internal Implementation

The frame protocol is used internally when server functions return both serialized data and raw streams:
The client automatically decodes frames and reconstructs the data.

Streaming Patterns

Progressive Data Loading

Load and display data progressively:

Parallel Data Fetching

Load independent sections in parallel:

Nested Suspense

Create sophisticated loading experiences:

Performance Optimization

Chunk Size

Control streaming chunk size for optimal performance:

Selective Streaming

Don’t stream everything - use Suspense strategically:

Preloading Critical Data

Load critical data in route loaders:

Debugging Streaming

Streaming can be harder to debug. Use these techniques:

Log Stream Events

Network Inspection

In browser DevTools:
  1. Open Network tab
  2. Click on the streaming request
  3. Watch the Response tab update in real-time

Disable Streaming Temporarily

Switch to string rendering to debug:

Best Practices

Streaming improves perceived performance for most applications:
Wrap slow-loading content, not everything:
Show skeletons that match final content:
Use browser DevTools to throttle network speed and test streaming behavior.
Track First Contentful Paint (FCP) and Time to Interactive (TTI) to measure streaming impact.

Server Rendering

Learn how SSR enables streaming

Server Functions

Stream data from server functions

SSR & Streaming Guide

Complete guide to SSR and streaming

Deployment

Deploy streaming applications