SSE
tanstack-fetch/sse is framework-agnostic. Optional useSse helpers live in tanstack-fetch/react, /vue, /solid, /angular, and /svelte.
Need two-way messages or NDJSON? See WebSocket, WebTransport & streams (tanstack-fetch/live, which also includes api.sse).
EventSource cannot set Authorization. Use tanstack-fetch/sse (api.sse) for authenticated streams — see /recipes/eventsource-auth-headers.
Use the Framework picker in the header to show one stack at a time.
Core — api.sse
Framework
Core (framework-agnostic) · tanstack-fetch/sse
Live demo
Live demo · SSE
api.sse over fetch
Real tanstack-fetch/sse against a mock event stream — cookies / Authorization work (unlike EventSource).
Idle — start the stream
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/react'
const api = createFetch({
plugins: ['sse-resume'],
getToken: () => localStorage.getItem('access_token'),
})
const OrdersLive = () => {
const { data, status, error, close } = useSse<Tick>('/orders/stream', {
client: api,
})
if (status === 'error') return <p>{error?.message}</p>
return (
<>
<p>{status} · tick #{data?.n}</p>
<button onClick={close}>Close</button>
</>
)
}import { createFetch } from 'tanstack-fetch/sse'
const api = createFetch({
baseUrl: 'https://api.example.com',
plugins: ['sse-resume'],
getToken: () => localStorage.getItem('access_token'),
})Simple handlers
const stream = api.sse<OrderEvent>('/orders/stream', {
onMessage: (data) => console.log(data),
})
stream.close()Async iteration
for await (const event of api.sse<OrderEvent>('/orders/stream', { signal })) {
console.log(event.data)
}TanStack Start
Framework
TanStack Start · tanstack-fetch/react · browser-only stream
SSE is a client concern. Open the stream in a route component (or a child that only mounts in the browser). Prefer router context for the shared api / Query client; keep useSse in the component.
import { createFileRoute } from '@tanstack/react-router'
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/react'
const api = createFetch({ plugins: ['sse-resume'] })
export const Route = createFileRoute('/orders/live')({
component: OrdersLive,
})
const OrdersLive = () => {
const { data, status, close } = useSse<OrderEvent>('/orders/stream', { client: api })
return (
<div>
<p>{status}</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
<button type="button" onClick={close}>
Stop
</button>
</div>
)
}Remix
Framework
Remix · Client Component / browser-only
Do not open SSE inside a loader. Use a client module (or ClientOnly) with useSse from tanstack-fetch/react — same as React.
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/react'
const api = createFetch({ plugins: ['sse-resume'] })
export const OrdersLive = () => {
const { data, status, close } = useSse<OrderEvent>('/orders/stream', { client: api })
return (
<div>
<p>{status}</p>
<button type="button" onClick={close}>
Stop
</button>
</div>
)
}SolidStart
Framework
SolidStart · tanstack-fetch/solid · browser-only
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/solid'
const api = createFetch({ plugins: ['sse-resume'] })
const OrdersLive = () => {
const { data, status, close } = useSse<OrderEvent>('/orders/stream', { client: api })
return (
<div>
<p>{status()}</p>
<pre>{JSON.stringify(data(), null, 2)}</pre>
<button type="button" onClick={close}>
Stop
</button>
</div>
)
}Keep the stream out of server entry / SSR load functions.
React useSse
Framework
React · tanstack-fetch/react · Next.js Client Components
Live demo
Live demo · useSse
React useSse + status
Pass {'{ client: api }'} — no FetchProvider required. Status: connecting → connected → disconnected / error.
status: disconnected
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/react'
const api = createFetch({
baseUrl: import.meta.env.VITE_API_URL,
plugins: ['sse-resume'],
getToken: () => localStorage.getItem('access_token'),
})
const OrdersLive = () => {
// Pass client — FetchProvider is optional
const { data, status, error, close } = useSse<Tick>('/orders/stream', {
client: api,
})
if (status === 'error') return <p>{error?.message}</p>
return (
<div>
<p>{status}</p>
<p>{data ? `#${data.n}` : '—'}</p>
<button type="button" onClick={close}>Disconnect</button>
</div>
)
}import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/react'
const api = createFetch({ plugins: ['sse-resume'] })
const LiveFeed = () => {
const { data, status, error, close } = useSse<OrderEvent>('/orders/stream', {
client: api,
})
if (status === 'error') return <p>{error?.message}</p>
return (
<div>
<p>{status}</p>
<p>{data?.id}</p>
<button type="button" onClick={close}>
Stop
</button>
</div>
)
}Example: examples/sse-live · React guide
Vue / Nuxt useSse
Framework
Vue 3 / Nuxt · tanstack-fetch/vue
<script setup lang="ts">
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/vue'
const api = createFetch({ plugins: ['sse-resume'] })
const { data, status, error, close } = useSse<OrderEvent>('/orders/stream', {
client: api,
})
</script>
<template>
<p v-if="status === 'error'">{{ error?.message }}</p>
<div v-else>
<p>{{ status }}</p>
<p>{{ data?.id }}</p>
<button type="button" @click="close">Stop</button>
</div>
</template>Guide: Vue & Nuxt
Next.js
Framework
React · Next.js App Router
Use useSse in a Client Component ('use client').
'use client'
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/react'
const api = createFetch({
baseUrl: process.env.NEXT_PUBLIC_API_URL,
plugins: ['sse-resume'],
})
export const OrdersLive = () => {
const { data, status, close } = useSse<OrderEvent>('/orders/stream', { client: api })
return (
<div>
<p>{status}</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
<button type="button" onClick={close}>
Stop
</button>
</div>
)
}Solid
Framework
Solid · tanstack-fetch/solid
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/solid'
const api = createFetch({ plugins: ['sse-resume'] })
const OrdersLive = () => {
const { data, status, error, close } = useSse<OrderEvent>('/orders/stream', {
client: api,
})
if (status() === 'error') return <p>{error()?.message}</p>
return (
<div>
<p>{status()}</p>
<pre>{JSON.stringify(data(), null, 2)}</pre>
<button type="button" onClick={close}>
Stop
</button>
</div>
)
}Guide: Solid
Angular
Framework
Angular · tanstack-fetch/angular
import { Component } from '@angular/core'
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/angular'
const api = createFetch({ plugins: ['sse-resume'] })
@Component({
selector: 'app-orders-live',
template: `
<p>{{ status() }}</p>
<pre>{{ data() | json }}</pre>
<button type="button" (click)="close()">Stop</button>
`,
})
export class OrdersLiveComponent {
private readonly stream = useSse<OrderEvent>('/orders/stream', { client: api })
readonly data = this.stream.data
readonly status = this.stream.status
readonly close = this.stream.close
}Guide: Angular
Svelte / SvelteKit
Framework
Svelte / SvelteKit · tanstack-fetch/svelte
<script lang="ts">
import { createFetch } from 'tanstack-fetch/sse'
import { useSse } from 'tanstack-fetch/svelte'
const api = createFetch({ plugins: ['sse-resume'] })
const { data, status, error, close } = useSse<OrderEvent>('/orders/stream', {
client: api,
})
</script>
{#if $status === 'error'}
<p>{$error?.message}</p>
{:else}
<p>{$status}</p>
<pre>{JSON.stringify($data, null, 2)}</pre>
<button type="button" on:click={close}>Stop</button>
{/if}Keep streams in browser components. Guide: Svelte
Why not EventSource for auth
EventSource cannot set custom headers (Authorization). Use tanstack-fetch/sse (api.sse) instead. See /recipes/eventsource-auth-headers (problem tutorial) and /guide/plugins (sse-resume).
Cache updates with Query
Inside onMessage, update Query state directly so the stream feeds your UI without a second fetch:
const stream = api.sse<OrderEvent>('/orders/stream', {
onMessage: (data) => queryClient.setQueryData(['orders'], (prev) => ...),
})Link to /guide/tanstack-query for full useQuery / useMutation wiring.
