Optimize your Nextjs app
Tags: nextjs, optimization, lighthouse, lazyloading
Published: 2024-03-22 18:00:37

What I did to investigate the performance of my application.

When you’re working on a Next.js app, you’ve probably had those moments where you’re like, ‘Why is the app moving so slowly?’ So, you decide to play detective with Lighthouse, only to find out that the performance is far from great. I’ve just wrapped up some performance tuning and picked up a few valuable insights worth remembering during development. I’d like to leave it here as my memorandum.

In this article, I assume the Nextjs 13. ~ app directory.

**1. Use Built-In Optimization Feature**

Nextjs comes with a variety of built-in optimizations to improve your application’s speed. There are many kinds of optimization available, I think these features are the most common and easy to apply to your application.

Image: Nextjs extends the traditional <img> element in HTML, which leads to optimizing the image. You can use <Image /> component

font: next/font optimizes any font file and removes external network requests to improve performance. It automatically self-hosts any Google Font, so no requests are sent to Google by the browser.

**2. Remove unused packages**

Sometimes we forget to remove packages that are defined in package.json but are no longer needed. You can check those items by running npx depcheck.

![](https://miro.medium.com/v2/resize:fit:640/format:webp/1*VD1-M-5kO5Lc-qczTjf2Jg.png)

**3. Check the current bundle size**

Run yarn build and check each page’s First Load JS size. You can find which page requires a bunch of modules and potentially runs slow. If you see the text color red, you could investigate this file deeper.

![](https://miro.medium.com/v2/resize:fit:640/format:webp/1*mZgZeg7z1pqAH8XRRllxtg.png)

@next/bundle-analyzer enables you to visually analyze the bundle size. The bigger the cell is, the larger the size of the modules. The installation guide is available in the document.

[https://www.npmjs.com/package/@next/bundle-analyzer?source=post_page-----e4fe9718fc8a--------------------------------](https://www.npmjs.com/package/@next/bundle-analyzer?source=post_page-----e4fe9718fc8a--------------------------------)

![](https://miro.medium.com/v2/resize:fit:720/format:webp/1*qkrFZxW0H-L3PckFlqQp_Q.png)

As the image above shows, the pdf.js module takes up a lot of space, which is causing a huge first load js bundle size on the /document page.

**4. Lighthouse**

If you are using Google Chrome, you can use Lighthouse, an open-source tool that can help you improve your website’s speed, performance, and overall experience.

[https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?source=post_page-----e4fe9718fc8a--------------------------------](https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?source=post_page-----e4fe9718fc8a--------------------------------)

I’m not going to write about the detailed usage of the lighthouse, but you can run the diagnoses and see the report on your application. It will give us some metrics and diagnostics, and you can check which element or aspect is the touchstone and have room for improvement.

![](https://miro.medium.com/v2/resize:fit:720/format:webp/1*-ifBqfNXqeJ7HzQ9i1_yKw.png)

In the example above, I’ve got a warning that says “Largest Cotentfull Paint image was lazily loaded”. LCP measures the time it takes for the largest content element(such as text, images, videos, etc) to appear on the screen. If the largest content element of your page is not optimized, this index scores lower. You can improve this by adding priority tag in <Image /> component.

// for the largest image element
 <Image
   src='/cat.jpg'
   alt='cute-cat'
   priority
   ....
 />


In the <Image /> component, the default setting of priority is false, meaning it applies lazy loading. When you add priority={true}(or just 'priority'), the image will be considered high priority and preloaded, which will shorten the LCP time.

**5. Dynamic Import**

We can use next/dynamic for the modules or components that are rendered for the first time on the client side to improve the performance.

[https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading?source=post_page-----e4fe9718fc8a--------------------------------](https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading?source=post_page-----e4fe9718fc8a--------------------------------)

In my example, I made a PDFRenderer component, which will show the PDF images in the modal when the user clicks the ‘open modal’ button on the page.

![](https://miro.medium.com/v2/resize:fit:640/format:webp/1*AnJQ3DocsMl155UmpluazA.png)

![](https://miro.medium.com/v2/resize:fit:720/format:webp/1*2zx4uLtkR5sMwRZbZvrJvA.png)

In this modal component, I imported some modules for rendering PDF, but this module is needed only when the user clicks the button and opens the modal. In other words, some modules that are not required to show the initial page view could be excluded from the first load js of the page. This is when next/dynamic comes in handy. I’ve changed the import statements to something like this.

// /document page
// Inside the PDFModal, I imported a bunch of node modules...

// Before
import PDFModal from '@/components/optimization/PDFModal';

// After
import dynamic from 'next/dynamic';
const PDFModal = dynamic(() => import('@/components/optimization/PDFModal'), {ssr: false});


By doing this, when the browser runs the javascript for the /document page, it applies lazy loading for the PDFModal component and only includes them when they are needed.

![](https://miro.medium.com/v2/resize:fit:640/format:webp/1*q9B31dMN3t7dHFsc6pI-kw.png)

At first, the /document page had 187 kb first bundle js, and now it’s compressed to over half of the size!

**Conclusion**
These key aspects are crucial during development. Understanding potential obstacles to your application’s smooth operation and taking advantage of the Nextjs optimization system while developing, it’ll be easier to do performance tuning after deploying. I hope this article gives you some hints to improve your Nextjs application!