Search code examples
performancenext.jsoptimizationpage-load-timelargest-contentful-paint

How to diagnose slow nextjs page and speed up initial and subsequent load times


I have an app router dashboard page which renders a lot of thumbnails & images on the viewport and beneath it. it is done by some client components and some RSCs

Happens in dev mode

bun run dev 
"dev": "next dev --turbo",

However, LCP times vary from ~10 s to 1.5 minutes

Ideally, I would like everything loaded in <5 sec and be responsive, but in its current state it is extremely slow and sluggish

For context
The page images are not internal to the server, they are third party 'image.tmdb.org', 'i.scdn.co' as defined in next.config.js

The backend performs some db joins and has cached static data, and it sends the image urls to the webapp

I need clarity on what is causing the slowness because I find it hard to debug

The ~30s of scripting in the Profiler chart in the chrome performance screenshot seems like a bottleneck

I am:

  • Using <Image/> from next/image which is set to lazy load and webp
  • Using memo on some react client components which receive content from a useQuery hook
'use client'
export const CarouselCard = ({ data }: any) => {
  ...
 return useMemo(() => {
    return(
       ...
               <Image
                  src={`${TMDB_IMAGE_BASE_URL}${data.imageurl}`}
                  width={300}
                  height={60}
                  alt="Movie/TV Show logo"
                  className="mb-2"
                />
    ...

  )
}

const ContentCarousel = ({
  options,
  collectionType,
}: CarouselProps) => {
  const { collA, collB, collC } =
    useLibraryContext();
    
  let data;
  let isLoading;

  switch (collectionType) {
    case 'A':
      data = collA;
      isLoading = false;
      break;
    case 'B':
      data = collB;
      isLoading = false;
      break;
    case 'C':
      data = collC;
      isLoading = false;
      break;
    default:
      const queryResult = api.imagesRouter.queryMedia.useQuery(options);
      data = queryResult.data;
      isLoading = queryResult.isLoading;
      break;
  }

    return (
       <Carousel
        opts={{
          align: 'start',
          loop: true,
        }}
        className="grid relative w-full"
      >
        <CarouselContent className="-ml-1">
          {isLoading
            ? Array.from({ length: 25 }).map((_, idx) => (
                <CarouselItem key={idx} className={cn('pl-1', className)}>
                  <div className="flex flex-col space-y-3">
                    <Skeleton className="h-[125px] w-[250px] rounded-xl" />
                  </div>
                </CarouselItem>
              ))
            : data?.map((item, idx) => {
               ...
                return (
                  <CarouselItem
                    key={idx}
                    className={cn('pl-1', className)}
                  >
                    <div className="p-1">
                      <CarouselCard data={item} />
                    </div>
                  </CarouselItem>
                );
              })}
        </CarouselContent>
        <CarouselPrevious />
        <CarouselNext />
      </Carousel>
    )
// dashboard/page.tsx

const Dashboard = async () => {
    return (
    <React.Fragment>
      ...
      <ContentCarousel options = {{}}/>
       <ContentCarousel ...
    )
}

  • I stopped displaying some svgs with huge amount of miniature DOM elements, but it has not improved the response time

Added screenshots
Thanks in advance

edit 1: found this author helpful https://dev.to/codesensei/optimizing-performance-in-nextjs-13-applications-techniques-for-faster-rendering-1b6l

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here


Solution

  • Solved by

    • caching static db data for large queries
    • converting most to react server components
    • using sensible defaults like limiting rows with overflow components to a cap of 25 components

    p90 Response times are ~5s