next.js: Suspense in production is blocking rather than showing fallback UI

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.6.0: Wed Jul  5 22:22:52 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T8103
    Binaries:
      Node: 16.20.2
      npm: 8.19.4
      Yarn: N/A
      pnpm: N/A
    Relevant Packages:
      next: 13.4.19
      eslint-config-next: 13.4.16
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.1.6
    Next.js Config:
      output: N/A

Which area(s) of Next.js are affected? (leave empty if unsure)

App Router

Link to the code that reproduces this issue or a replay of the bug

n/a

To Reproduce

Just create a component in the page.js and wrap any internal component with Suspense and add a fallback UI. Deploy the application on the ec2 server with the “next build” & “next start”. The fallback UI doesn’t come on the client side instead it waits for the complete UI to load.

Describe the Bug

I am facing an issue with the suspense streaming.

I have used suspense in the page.js and added a fallback UI for that (not using loading.js and instead using suspense in the component itself) Everything is working fine in the DEV environment but in the PROD the suspense fallback is not showing at all instead it is waiting for the complete UI to load.

It is ruining the complete UX for the users as the user doesn’t know that some background process is ongoing.

Expected Behavior

As soon as the navigation starts or refreshes the page, the loading fallback UI should show up.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Reactions: 28
  • Comments: 39 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Hello, i have the same issue in next 13.5.4 when is deployed in AWS Amplify. This problem doesn’t happens in dev mode or running local build.

I developed a project using suspense and loading.jsx.

Loading.jsx fallback is perfect, but with suspense in Aws Amplify, the page frozes and doesn’t show the fallback, when the loading finish, the suspense show their children.

My repository

https://github.com/TheBaronRojo/Loadingtest

And the Aws Amplify project

https://master.d3mh90mxynovfi.amplifyapp.com/suspense/subsuspense

“Update”

In Vercel this problem doesn’t happen

https://loadingtest.vercel.app/

So its a bug I was struggling with my code , thanks @jvandenaardweg for sharing a live example

I found a solution to make Suspense work properly on normal pages that are not dynamic, e.g. [id].

You should have it enabled: export const dynamic = "force-dynamic";

Tried this, but it does not work. When you throttle the network connection you’ll still see the same behaviour: the loading indicator is not instant or will not show up at all. You’ll still have no idea something is loading.

Just to clarify: throttling the connection is just a way to test out your website using sub optimal network connections, which can happen to any user anywhere in the world. It seems like this Streaming Suspense feature is only working when you have a perfect connection.

Having the same issue as the OP, I have multiple components wrapped in Suspense inside a page.tsx marked it with “force-dynamic” but when I click on a link that navigates to that page, nothing happens and the site looks unresponsive and only navigates once all the Suspense boundaries are resolved.

In local development it works as expected Link navigates instantly and I see the fallback UI, smells like a Vercel hosting issue.

@Vk-jangid or @leerob can you remove the label please add a complete reproduction ? There’s a reproduction case in my comment above

Found out i’m experiencing the same from a different issue here: https://github.com/vercel/next.js/issues/43548#issuecomment-1755556341

To quote myself, with a reproduction case:

I guess my issue lies in the use of <Suspense> on a page to have fine grained control over what component is loading, instead of a page wide loading indicator.

Using Vercel’s app router demo to demonstrate:

No issue here when using a generic loading.tsx file: https://app-router.vercel.app/loading

But the issue is here “Streaming with Suspense”: https://app-router.vercel.app/streaming

When you throttle the connection, using loading.tsx instantly shows a indicator. Which is good. But using the same throttled connection on the Streaming With Suspense demo prevents anything from being shown until a certain point. Not really clear when that exactly is.

Both also tested with the latest NextJS version locally and with a deploy on Vercel.

So the issue lies in the use of <Suspense> with a fallback on a page.tsx. When I switch over to using the loading.tsx the issue dissapears in my project. But that’s not what I hoped, I really want to use the Suspense fallback on a per component basis and not have a loading.tsx on the page level.

So, to summarize:

  1. Go to https://app-router.vercel.app/streaming
  2. Throttle your connection in Dev Tools, using slow/fast 3G or something
  3. Click “Edge Runtime” tab (or Node Runtime, it doesn’t really matter which one)

You’ll notice it takes a while to load but the Suspense fallback loading indicator will not show up. Where you would expect to have that loading indicator to be shown instantly, like with a page wide loading.tsx

Code: https://github.com/vercel/app-playground/tree/main/app/streaming

I think this is because the code for showing the fallback lives on the server, instead of the client? So it needs to do a fetch first to even know if it should show a loading indicator. But that’s a big issue when you have a sub optimal connection, which can happen anywhere. So wether to show a loading indicator or not should live in the client, not the server. Or should be known already by using the prefetch in the background on page load. Please correct me if i’m wrong on any of this, I’m kinda guessing here as I don’t know much about the NextJS/React internals.

anyone found a workaround yet? mine works on vercel but not on other hosting platforms like azure

Its really surprising that dev environment seems faster

https://github.com/vercel/next.js/assets/59060246/bc9b8b41-27da-49ba-b806-390fb4cb3ef5

I have the same issue. I’m working with next Js latest version, when I’m coding in my localhost everything is working as expecting, also in vercel I have not trouble to see the loading fallback in suspense component. But when I deploy to Amplify is not working. Actually I tried adding a delay for 8 second to try if in any time load my components but Im only can see the page is loading in browser tab and the page render after the delay is done. I don’t know what to try. I set the build Amplify to use a node js docker image version 18 and the last version of next Js but is not working. If anyone have a solution appreciate it.

Thanks folks! Made a PR to add this note to disable buffering for self-hosting with streaming in the docs.

Found out i’m experiencing the same from a different issue here: #43548 (comment)

To quote myself, with a reproduction case:

I guess my issue lies in the use of <Suspense> on a page to have fine grained control over what component is loading, instead of a page wide loading indicator. Using Vercel’s app router demo to demonstrate: No issue here when using a generic loading.tsx file: https://app-router.vercel.app/loading But the issue is here “Streaming with Suspense”: https://app-router.vercel.app/streaming When you throttle the connection, using loading.tsx instantly shows a indicator. Which is good. But using the same throttled connection on the Streaming With Suspense demo prevents anything from being shown until a certain point. Not really clear when that exactly is. Both also tested with the latest NextJS version locally and with a deploy on Vercel. So the issue lies in the use of <Suspense> with a fallback on a page.tsx. When I switch over to using the loading.tsx the issue dissapears in my project. But that’s not what I hoped, I really want to use the Suspense fallback on a per component basis and not have a loading.tsx on the page level.

So, to summarize:

  1. Go to https://app-router.vercel.app/streaming
  2. Throttle your connection in Dev Tools, using slow/fast 3G or something
  3. Click “Edge Runtime” tab (or Node Runtime, it doesn’t really matter which one)

You’ll notice it takes a while to load but the Suspense fallback loading indicator will not show up. Where you would expect to have that loading indicator to be shown instantly, like with a page wide loading.tsx

Code: https://github.com/vercel/app-playground/tree/main/app/streaming

I think this is because the code for showing the fallback lives on the server, instead of the client? So it needs to do a fetch first to even know if it should show a loading indicator. But that’s a big issue when you have a sub optimal connection, which can happen anywhere. So wether to show a loading indicator or not should live in the client, not the server. Or should be known already by using the prefetch in the background on page load. Please correct me if i’m wrong on any of this, I’m kinda guessing here as I don’t know much about the NextJS/React internals.

Even on a fast 1GB connection if I go to https://app-router.vercel.app/streaming and click on either “Edge Runtime” or “Node Runtime” nothing happens and then after x amount of time we navigate to the page we clicked on.