DEV Community

lokesh sunhare
lokesh sunhare

Posted on • Edited on

Make Your Next.js App Fly: Performance Hacks That Work

Introduction

There were times when the site felt painfully slow and completely unresponsive moments that left me frustrated and tempted to just give up that's why the Performance optimization is a critical aspect of developing web applications. Users expect applications to load quickly and respond to their interactions smoothly.

When a site takes over 1 second to become interactive, users often lose focus, and their experience feels interrupted.

No lengthy talk here’s the result that speaks for itself.

Imag-1
Back then, performance rate was crawling at 47

Image-2
Voila 🎉 near-perfect 96 in performance.

Want to check your site’s performance? Just head over to Google’s performance tool pagespeed.web.dev drop site URL, and hit Analyze. You can also use Chrome DevTools open Inspect, navigate to the Lighthouse tab, choose your desired device, mode, and categories, then click Analyze page state to see how your site stacks up.

Optimizing performance in the React ecosystem especially when using frameworks like Next.js, offers many tools to improve mobile and web performance, which is key to delivering fast, responsive applications that keep users engaged and satisfied.

First need to understand the Core Web Vitals. The Foundation of Web Performance.

Core Web Vitals are a set of metrics defined by Google to measure the quality of a user's experience on a website. These metrics focus on three key aspects: loading, interactivity, and visual stability.

Few Core Web Vitals

  1. First Contentful Paint (FCP)
    • What it measures: Loading performance (time to render the largest visible element)
    • Good threshold: Less than 2.5 seconds
  2. Largest Contentful Paint (LCP)
    • What it measured: Time from first user interaction to browser response
    • Good threshold: Less than 2.5 seconds
  3. Cumulative Layout Shift (CLS)
    • What it measures: Visual stability (unexpected layout shifts)
    • Good threshold: Less than 0.1 seconds
  4. Total Blocking Time (TBT)
    • What it measured: Total amount of time a webpage is blocked from responding
    • Good threshold: Less than 200 milliseconds

Here is the Diagnostics, Inspect each section individually and focus on improving the essentials.

vitals

let's break down the techniques for optimizing the performance of our React/Next.js application.

  • Optimize the CSS
    • In this project, there were some CSS files used in a few components, each containing around 4,500 lines of code. We removed unused styles, optimized, and minified the CSS, reducing the total lines by 50%.
    • Since CSS is render-blocking, it loads before the page is rendered, which can negatively impact performance if not optimized. This improves the FCP
    • Add <link> tag in the <head> to Prefetch and preload <link rel="preload"> or <link rel="prefetch"> this really helps to improve my performance.
<link rel="preload" as="image" href="/herobg.webp" fetchPriority="high" />

<link
  rel="preload"
  href="/styles/globals.css"
  as="style"
  onLoad="this.onload=null;this.rel='stylesheet'"
/>
<noscript>
  <link rel="stylesheet" href="/styles/globals.css" />
</noscript>
Enter fullscreen mode Exit fullscreen mode
  • Reduce JavaScript Bundle Size
    • Mobile devices struggle with parsing and executing large JS bundles. This improves the LCP
    • Use dynamic imports with SSR disabled for non-critical components.
  • Reduce Initial Load
    • Lazy-load non-critical components.
    • Use dynamic imports (next/dynamic) or load below-the-fold sections conditionally.
const NonCriticalComponent = dynamic(() => import('../components/NonCriticalComponent'), {
  ssr: false,
});
Enter fullscreen mode Exit fullscreen mode
  • Optimize Images
    • Mobile devices have smaller screens and limited bandwidth.
    • Use Next.js next/image which automatically serves optimized images.
    • Also, prefetch the image in the <head> tag with fetchPriority = "high" to reduce initial rendering time.
    • Serve WebP or AVIF formats for better compression, avoid heavy images.
    • Set proper image sizes via sizes attribute for responsive behavior.
 <Image
  src="/herobg.webp"
  alt="hero-bg"
  fill
  priority  // to load on priority 
  sizes="100vw"
  className="object-cover"
/>
Enter fullscreen mode Exit fullscreen mode
  • Optimize Fonts
    • Use font-display: swap, preload: true to prevent blocking rendering.
    • Prefer system fonts or serve self-hosted fonts with proper subsets.
    • Initially, our project used multiple fonts like Helvetica and Inter. To optimize performance, We minimized font usage and switched to using only Poppins.
import { Poppins} from 'next/font/google';
const poppins = Poppins({ subsets: ['latin'], display: 'swap', preload: true, });
Enter fullscreen mode Exit fullscreen mode
  • Leverage next/script for control
    • Lazy load scripts in the <head> tag to improve initial rendering performance.
    • Using attributes like async or defer for non-critical scripts in the <head> ensures they don’t block the DOM rendering process.
    • To optimize script loading, import also add the strategy to "lazyOnload"
<Script src="https://example.com/script.js" strategy="lazyOnload" />
Enter fullscreen mode Exit fullscreen mode
  • Memoizationl
    • In our project there is few components dealing with computationally intensive or frequently called functions with the same input values, as it helps avoid redundant calculations and improves the overall efficiency of the application.
    • memoization: React.memo(), useMemo(), and useCallback().
const memoizedValue = useMemo(() => expensiveComputation(count), [count]);
const memoizedIncrement = useCallback(requiredFunction, [count]);
Enter fullscreen mode Exit fullscreen mode
  • Code Splitting
    • Code splitting in React is a powerful technique that breaks down large components into smaller, reusable pieces helping to reduce code redundancy and avoid duplication for better performance and maintainability.

There are countless ways to boost performance in a Next.js app, but these are the techniques I personally implemented and they made a measurable impact on improving web vitals and overall user experience.

Conclusion

I’ve implemented all the above techniques in my own Next.js project and honestly, it wasn’t all smooth sailing. There were moments of frustration, especially when I applied the wrong optimizations or misunderstood how certain features worked. But through trial and error, learning from performance bottlenecks, and diving deeper into how React really works under the hood, we started to see real improvements.

What I’ve shared above isn’t just theory these are practical, concise strategies that helped me boost performance in a meaningful way. If you’re going through a similar journey, I hope these insights save you some time (and debugging headaches).

So that’s it, folks! I’d love to hear your thoughts or experiences with performance optimization techniques.

Top comments (2)

Collapse
 
dotallio profile image
Dotallio

Love how practical this is, especially breaking down what's actually worth focusing on. Did you hit any surprises with dynamic imports or image optimization that tripped you up at first?

Collapse
 
lokesh_sunhare_cd0ac18643 profile image
lokesh sunhare

Yes, Dynamic imports really do work wonders being able to load components only when needed made a noticeable difference. And image optimization seriously blew my mind too just tweaking formats like converting from JPG/PNG to WebP and AVIF and using next/image gave huge performance boosts without compromising quality.