What this usually means
Next.js streaming SSR can quietly fail when a component suspends indefinitely, a data fetch rejects but isn’t caught, or a Node.js stream is interrupted (e.g., premature client disconnect). Because the stream is chunked, errors late in render often surface as blank or cut-off output, not stack traces. If you rely on await in server components or fetch long-tail APIs, you’re vulnerable to these non-obvious hangs and partial renders.
The first ten minutes — establish facts before touching code.
- 1Use curl with --no-buffer (e.g., curl --no-buffer http://localhost:3000/yourpage) to monitor real-time streaming.
- 2Enable DEBUG=next:*,react:* in your environment to surface low-level SSR logs.
- 3Tail Node.js process logs: tail -f .next/trace | grep 'Error' or tail -f logs/production.log.
- 4Profile server response timings in Chrome DevTools — watch for 'Content Download' phase stalling.
- 5Temporarily replace all await fetch calls with hardcoded resolves to isolate slow/external dependencies.
- 6Wrap all server components in ErrorBoundary and log thrown errors to a file for inspection.
The specific files, logs, configs, and dashboards that usually own this bug.
- searchpages/_middleware.js and custom server entry (e.g., server.js) for custom streaming handlers or middlewares.
- searchThe .next/trace directory for low-level Next.js and React Server Components traces.
- searchEdge function logs if using Vercel or similar platforms (find 504s or incomplete invocations).
- searchServer component source for uncaught Promise rejections or missing Suspense fallbacks.
- searchbrowser DevTools 'Network' > Response tab for abrupt HTML cut-offs.
- searchDatadog/New Relic APM traces for long-running or hung requests.
Practical causes, not theory. These are the things you will actually find.
- warningA server component or fetch call that hangs on a slow backend or waits forever (no timeout).
- warningStreaming interrupted by unhandled promise rejection — process doesn’t crash, but stream is left incomplete.
- warningAccidental API calls to localhost:3000 inside SSR (infinite recursion).
- warningCustom Node.js middleware that closes the response stream prematurely.
- warningUsage of setTimeout or long-polling logic that never resolves during SSR.
- warningEdge platform streaming not supported for specific SSR features (e.g., Vercel edge runtime API mismatch).
Concrete fix directions. Pick the one that matches your root cause.
- buildWrap all network fetches in a timeout utility and log if they exceed 2–5s.
- buildAdd Suspense fallback boundaries at every async component layer to catch unresolved children.
- buildUpgrade to the latest Next.js minor — several SSR streaming bugs have been patched post-12.3.
- buildAvoid referencing window, document, or browser-only APIs in server components.
- buildLog stream 'close' and 'error' events on the Node.js response to catch hidden failures.
- buildIf using custom servers, explicitly pipe React's readable stream with error and end handlers.
A fix you cannot prove is a guess. Close the loop.
- verifiedcurl --no-buffer shows the entire HTML output, ending with </html>, in under 2s on local.
- verifiedAll components render, including slow or external-data-driven ones, when server-side logging is enabled.
- verifiedNo requests hang indefinitely in server logs; every request has a clear finish (200 or error).
- verifiedAutomated browser tests (e.g., Playwright) validate full page load and hydration.
- verifiedReact devtools confirm that all components are hydrated and present after SSR.
- verifiedSynthetic monitoring shows no requests stay open >5s under normal load.
Things that make this bug worse or harder to find.
- warningAssuming a 200 status code means the stream finished — always check for complete HTML.
- warningRelying only on browser logs; real failures often only show on the server side.
- warningLeaving unwrapped await calls in server components — always handle errors.
- warningBlindly retrying failed SSR deployments; root cause is often in application code, not the infra.
- warningSkipping Suspense boundaries — this is where hangs propagate silently.
- warningIgnoring edge deployment logs; streaming bugs manifest differently than on Node.js.
Silent Partial Renders in Streaming SSR on Next.js 13
Timeline
- 10:12PagerDuty fires for increased 504s on /dashboard.
- 10:15Initial inspection: all logs show 200 status, some responses incomplete.
- 10:18curl --no-buffer shows HTML output ending mid-div tag, stream never closes.
- 10:22Server code review finds unwrapped await fetch to a slow analytics API.
- 10:28Added 2s timeout to all data fetches with logging of slow responses.
- 10:31Re-deploy, curl and browser tests confirm full HTML returned and hydrated.
- 10:34Root cause postmortem: missing Suspense fallback allowed hung component to block stream.
We’d just rolled out a Next.js 13 update using streaming SSR on several dashboard pages. Users started reporting blank panels and, crucially, there were no errors in the Vercel edge logs or the browser.
Digging with curl revealed that the HTML sometimes cut off in the middle of a component tree — but the HTTP status was still 200. There was a hidden await fetch call to a 3rd-party analytics API that occasionally responded in 30s or more, but in some cases hung forever.
The fix was both to add a timeout wrapper to all API fetches, and to ensure Suspense fallbacks were actually wired up for every async server component. Post-fix, no more stuck streams, and the page hydrated cleanly every time.
Root cause
A server-side analytics fetch in a React Server Component hung indefinitely; no Suspense fallback meant the stream never completed.
The fix
All fetches now have a 2s timeout and async components are nested in Suspense boundaries with clear error handling.
The lesson
Streaming SSR can fail silently if any async code blocks or never resolves; production code must treat timeouts and Suspense as required, not optional.
Streaming SSR is only as reliable as the fastest async boundary. In practice, a single unresolved fetch or thrown promise can block the entire stream from finishing, but never show up as a stack trace.
I've seen cases where server logs were ‘clean’ and browser only showed partial renders. If your fetch isn’t wrapped with a timeout, assume it will eventually stall in production — even if your APIs are reliable in staging.
The browser hides SSR streaming details. Always inspect with curl --no-buffer and verify the HTML terminates properly. If a custom server is used, make sure response streams are piped with proper error and close handlers.
On Vercel or other edge platforms, their logging often truncates on client disconnects — check both server and edge logs for incomplete execution traces or abrupt cold starts.
Suspense isn’t optional for stability in streaming SSR. Every data-fetching component should be nested under one, or you risk global hangs.
If you migrate legacy pages, audit each tree for missing Suspense. Catch unhandled promise rejections for any async fetch and surface errors via fallback UIs, even if they’re just error logs in dev.
One subtle trap: making SSR API calls that hit your own Next.js routes (e.g., fetch('/api/user') in a server component). This can create infinite loops, leading to unclosed streams with no obvious trace except resource exhaustion.
Audit all fetch URLs. Fully qualify them and ensure you never hit SSR endpoints from inside SSR.
Frequently asked questions
Why does streaming SSR fail silently without error logs?
Most streaming failures come from unresolved Promises or hung fetches in server components. Node.js won’t crash, and Next.js often emits no error if no Suspense fallback is present; you see only partial HTML as the stream remains open.
How do I trace which component hung in a streaming SSR response?
Enable DEBUG=next:*,react:* and add explicit logging at every async server component. Instrument fetches with timing logs and use Suspense boundaries with custom fallbacks for granular visibility.
Can custom server logic break streaming SSR?
Absolutely. If you pipe streams incorrectly or close the HTTP response early (before React finishes rendering), clients will get truncated HTML. Carefully audit all low-level middleware and test raw responses.
Is this specific to certain Next.js versions?
Streaming bugs are more common in Next.js 12–13, especially before minor releases fixed incompatibilities with React 18. Always check release notes and upgrade if you suspect a framework-level bug.
How can I simulate real-world streaming failures locally?
Mock slow endpoints in your server components (e.g., fetch with setTimeout) and watch how the SSR stream behaves in curl. Remove all Suspense boundaries and see how the app breaks — this surfaces real failure paths.