Hi Team
Problem Summary
I have a Next.js 15 app using AI SDK v5 with OpenRouter that shows streaming responses working perfectly on the server side (console shows all text-delta parts), but the UI displays the complete response all at once instead of streaming word-by-word.
Tech Stack
- AI SDK: v5 (latest)
- Next.js: 15
- Provider: OpenRouter (Claude Sonnet 4, GPT-4o, etc.)
- Streaming: Server-Sent Events with resumable streams
- UI: React with
useChathook
Server-Side Evidence (Working)
🔥 STREAM PART: {"type":"text-delta","id":"gen-xxx","delta":"Hi "}🔥 STREAM PART: {"type":"text-delta","id":"gen-xxx","delta":"there, "}🔥 STREAM PART: {"type":"text-delta","id":"gen-xxx","delta":"Driss! "}// ... continues streaming properlyClient-Side Issue
- UI shows complete response instantly instead of streaming
useChatwithexperimental_throttle: 100- Using
JsonToSseTransformStream()in response - Resumable stream context with Redis
Key Code Snippets
API Route:
const stream = createUIMessageStream({ execute: ({ writer: dataStream }) => { const result = streamText({ model: userProvider.languageModel(selectedChatModel), experimental_transform: smoothStream({ chunking: 'word' }), // ... other config }); result.consumeStream(); dataStream.merge(result.toUIMessageStream({ sendReasoning: true })); }});
return new Response( streamContext ? await streamContext.resumableStream(streamId, () => stream.pipeThrough(new JsonToSseTransformStream()) ) : stream.pipeThrough(new JsonToSseTransformStream()));Client:
const { messages, status } = useChat<UIMessage>({ experimental_throttle: 100, transport: new DefaultChatTransport({ api: '/api/chat', fetch: fetchWithErrorHandlers, }), onData: (dataPart) => setDataStream(ds => [...ds, dataPart])});What I’ve Tried
- ✅ Verified
JsonToSseTransformStream()is used - ✅ Server logs show proper streaming parts
- ✅
smoothStream({ chunking: 'word' })configured - ✅
experimental_throttle: 100set - ❌ UI still shows complete response at once
Has anyone encountered similar issues where server-side streaming works but client-side doesn’t update incrementally?
Thanks