So I have a problem with my suspense in Next 15
. My Suspense fallback is not shown in production, but works as intended on localhost, even when ran with next build && next start
, so even with the production environment, but on localhost, it works.
I'm using SST with AWS
for deployment.
page.tsx:
export const dynamic = 'force-dynamic';
async function categories({
searchParams,
params,
}: {
searchParams?: Promise<{
query?: string;
page?: string;
}>;
params: Promise<{ id: string }>;
}) {
const businessId = (await params).id;
const search = await searchParams;
const query = search?.query || '';
const currentPage = Number(search?.page) || 1;
const res = await fetch(
`${protocol}://${process.env.MAIN_DOMAIN}/api/main/business/${businessId}/categories-pages?query=${query}`,
{
cache: 'no-store',
}
);
const response = await res.json();
const totalPages = response.pages;
console.log('TOTAL PAGES SERVER: ', totalPages);
return (
<div className='w-full'>
<div className='flex w-full items-center justify-between'>
<h1 className={`${lusitana.className} text-2xl`}>Categories</h1>
</div>
<div className='mt-4 flex items-center justify-between gap-2 md:mt-8'>
<Search placeholder='Search categories...' />
<LinkToCreate
link={'/dashboard/categories/create'}
text={'Create category'}
/>
</div>
<Suspense
key={query + currentPage}
fallback={<CategoriesTableSkeleton />}
>
<CategoriesTable searchParams={searchParams} businessId={businessId} />
</Suspense>
CategoriesTable.tsx:
export default async function CategoriesTable({
searchParams,
businessId,
}: {
searchParams?: Promise<{
query?: string;
page?: string;
}>;
businessId: string;
}) {
const search = await searchParams;
console.log('SEARCH OARAMS:::::::: ', search);
const query = search?.query || '';
const currentPage = Number(search?.page) || 1;
const url = `${protocol}://${process.env.MAIN_DOMAIN}/api/main/business/${businessId}/categories?page=${currentPage}&query=${query}`;
const response = await fetch(url, {
cache: 'no-store',
});
const res = await response.json();
const categories: CategoryInterface[] = res.categories;
return (<div>....</div>)
FIX I TRIED:
- No buffering accel:
/* config options here */
reactStrictMode: false,
async headers() {
return [
{
source: '/:path*{/}?',
headers: [
{
key: 'X-Accel-Buffering',
value: 'no',
},
],
},
];
},
- Tried moving
await searchParams
from my categoriesTable to mypage.tsx
entirely.
EDIT 1 :
It seems like this is a problem related to AWS cloud distribution which sends the data as a chunk instead of a stream response. However I did not find any fixes, so any advice is welcome.
I created a git for a minimal reproduction here: github
And the two deployments to view the results and compare:
-AWS DEPLOYMENT - where suspense is not shown
-VERCEL DEPLOYMENT - where suspense works as intended