<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Codexomation</title>
    <description>The latest articles on DEV Community by Codexomation (@codexomation).</description>
    <link>https://dev.to/codexomation</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4094851%2F07e0aff9-62ad-48e6-b2ad-df751af15e47.png</url>
      <title>DEV Community: Codexomation</title>
      <link>https://dev.to/codexomation</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codexomation"/>
    <language>en</language>
    <item>
      <title>Next.js Performance Optimization: Get 95+ PageSpeed Scores in 2025</title>
      <dc:creator>Codexomation</dc:creator>
      <pubDate>Thu, 27 Aug 2026 04:06:14 +0000</pubDate>
      <link>https://dev.to/codexomation/nextjs-performance-optimization-get-95-pagespeed-scores-in-2025-k20</link>
      <guid>https://dev.to/codexomation/nextjs-performance-optimization-get-95-pagespeed-scores-in-2025-k20</guid>
      <description>&lt;h2&gt;
  
  
  Why Performance Matters More Than Ever
&lt;/h2&gt;

&lt;p&gt;Google's Core Web Vitals have been a ranking factor since 2021. But beyond rankings, performance is user experience — and user experience is revenue.&lt;/p&gt;

&lt;p&gt;Amazon found that every 100ms of latency cost 1% in sales. Walmart reported a 2% conversion increase for every 1 second of improvement in page load time. These aren't ancient statistics — they're more relevant than ever as user expectations continue rising.&lt;/p&gt;

&lt;p&gt;Next.js is built for performance. But Next.js can still be slow if you don't understand which optimizations are defaults, which require explicit configuration, and which common patterns actively harm performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Core Web Vitals
&lt;/h2&gt;

&lt;p&gt;Google measures three Core Web Vitals:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Largest Contentful Paint (LCP):&lt;/strong&gt; How long until the largest visible element is rendered. Target: under 2.5 seconds. This is usually your hero image, hero text, or main content block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cumulative Layout Shift (CLS):&lt;/strong&gt; How much the page layout shifts during loading. Target: under 0.1. Caused by images without dimensions, dynamically injected content, and web fonts loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interaction to Next Paint (INP):&lt;/strong&gt; How quickly the page responds to user interactions. Target: under 200ms. This replaced FID (First Input Delay) in 2024.&lt;/p&gt;

&lt;p&gt;All three need to pass in "Good" range (75th percentile) for your URLs to be considered "Good" by Google.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js Performance Defaults (Free Wins)
&lt;/h2&gt;

&lt;p&gt;Next.js includes several performance features out of the box. Make sure you're not accidentally disabling them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic Code Splitting
&lt;/h3&gt;

&lt;p&gt;Next.js automatically splits your JavaScript bundle by route — each page only loads the JavaScript it needs. Don't work against this by importing large libraries at the root level when they're only needed in specific components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Components (App Router)
&lt;/h3&gt;

&lt;p&gt;With the App Router, components default to server components — they render on the server and send only HTML to the client. Zero JavaScript overhead for these components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This is a Server Component by default — no "use client" directive&lt;/span&gt;
&lt;span class="c1"&gt;// It renders on the server, sends HTML, zero JS bundle impact&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Direct DB access, no API round-trip&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only add "use client" when you actually need browser APIs, React hooks, or event listeners. Client components add to your JavaScript bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image Optimization
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;next/image&lt;/code&gt; automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Converts to WebP/AVIF&lt;/li&gt;
&lt;li&gt;Resizes for the device requesting it&lt;/li&gt;
&lt;li&gt;Lazy loads by default&lt;/li&gt;
&lt;li&gt;Prevents layout shift with required &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Always specify width and height (or use fill + parent with position:relative)&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;630&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hero image"&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt; &lt;span class="c1"&gt;// Add this to the above-the-fold image (disables lazy loading)&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common mistake:&lt;/strong&gt; Using &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; instead of &lt;code&gt;next/image&lt;/code&gt;. This bypasses all optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Font Optimization
&lt;/h2&gt;

&lt;p&gt;Fonts are one of the most common sources of both CLS and LCP degradation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using next/font
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Space_Grotesk&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Space_Grotesk&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Prevents invisible text during font load&lt;/span&gt;
  &lt;span class="na"&gt;variable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--font-space-grotesk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;next/font&lt;/code&gt; handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-hosting fonts (no Google Fonts round-trip)&lt;/li&gt;
&lt;li&gt;Automatic font preloading&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;font-display: swap&lt;/code&gt; to prevent invisible text&lt;/li&gt;
&lt;li&gt;Variable font slicing (only loads the weights you use)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Never do this in App Router:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Don't import Google Fonts via &amp;lt;link&amp;gt; in layout.tsx --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This causes an additional network round-trip and can't be preloaded optimally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eliminating Font-Related CLS
&lt;/h3&gt;

&lt;p&gt;CLS from fonts happens when the font loads and causes text reflow. Fix it with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;font-display: swap&lt;/code&gt; (already in &lt;code&gt;next/font&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;size-adjust&lt;/code&gt; CSS property to match fallback font metrics&lt;/li&gt;
&lt;li&gt;Or &lt;code&gt;next/font&lt;/code&gt;'s &lt;code&gt;adjustFontFallback: true&lt;/code&gt; option (experimental, but effective)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bundle Size Optimization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Analyze Your Bundle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @next/bundle-analyzer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// next.config.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;withBundleAnalyzer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@next/bundle-analyzer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANALYZE&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withBundleAnalyzer&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ANALYZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a visual map of your bundle. Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Libraries that are much larger than expected&lt;/li&gt;
&lt;li&gt;Duplicate packages (two versions of the same library)&lt;/li&gt;
&lt;li&gt;Libraries that should be lazy-loaded (charts, rich text editors, date pickers)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tree Shaking Anti-Patterns
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt; Import entire library&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Imports 70kb of lodash&lt;/span&gt;
&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt; Import only what you need&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/debounce&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Imports 1.5kb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Even better for simple utilities:&lt;/strong&gt; Use browser APIs or small focused packages&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Debounce without lodash&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lazy Loading Heavy Components
&lt;/h3&gt;

&lt;p&gt;Don't load components that aren't visible on first render:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/dynamic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This component's JavaScript only loads when it's needed&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HeavyChart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./HeavyChart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-64 bg-gray-100 animate-pulse rounded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// For components that use browser APIs&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Lazy load with intersection observer trigger (for below-fold)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;VideoPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./VideoPlayer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What to lazy load:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chart libraries (Chart.js, Recharts — often 200–300kb)&lt;/li&gt;
&lt;li&gt;Rich text editors (Tiptap, Quill — 200–400kb)&lt;/li&gt;
&lt;li&gt;Date/time pickers&lt;/li&gt;
&lt;li&gt;Video players&lt;/li&gt;
&lt;li&gt;Map libraries (Leaflet, Google Maps)&lt;/li&gt;
&lt;li&gt;Analytics and chat widgets&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Caching Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Static Generation (Best Performance)
&lt;/h3&gt;

&lt;p&gt;Pages with static data should use Static Generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// generateStaticParams makes these routes static at build time&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateStaticParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAllPosts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// No dynamic function = static page&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPostBySlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Static pages are served from CDN edge nodes — effectively zero time to first byte.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental Static Regeneration (ISR)
&lt;/h3&gt;

&lt;p&gt;For pages that need to stay updated without a full redeploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Regenerates every 60 seconds if requested&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revalidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Fetches fresh data on revalidation&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Route Segment Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Force dynamic rendering (when you need fresh data on every request)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;force-dynamic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Cache the route for 1 hour&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revalidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Image Optimization Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preloading Critical Images
&lt;/h3&gt;

&lt;p&gt;The hero image should load as fast as possible. Add &lt;code&gt;priority&lt;/code&gt; to images above the fold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;priority&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; to the document head, starting the image download earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Responsive Images
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;fill&lt;/span&gt; &lt;span class="c1"&gt;// Parent must have position: relative&lt;/span&gt;
  &lt;span class="na"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"&lt;/span&gt;
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"object-cover"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sizes&lt;/code&gt; attribute tells the browser what size the image will be at different viewport widths. This enables correct srcset generation, preventing the mobile browser from downloading a 1920px image for a 390px screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modern Image Formats
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;next.config.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;formats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/avif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AVIF is 50% smaller than WebP and 80% smaller than JPEG at the same quality. Not all browsers support it yet, but Next.js serves the appropriate format per browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Third-Party Script Optimization
&lt;/h2&gt;

&lt;p&gt;Third-party scripts (analytics, chat, ads) are the #1 cause of slow websites that look well-optimized in theory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using next/script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// strategy options:&lt;/span&gt;
&lt;span class="c1"&gt;// - "beforeInteractive": loads before page hydration (use sparingly)&lt;/span&gt;
&lt;span class="c1"&gt;// - "afterInteractive": loads after page hydration (default, most analytics)&lt;/span&gt;
&lt;span class="c1"&gt;// - "lazyOnload": loads during browser idle time (chat widgets, social embeds)&lt;/span&gt;
&lt;span class="c1"&gt;// - "worker": offloads to web worker (experimental, best performance)&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Script&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://www.googletagmanager.com/gtm.js?id=GTM-XXXXX"&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"afterInteractive"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chat widgets like Intercom should use &lt;code&gt;lazyOnload&lt;/code&gt; — they don't need to load until the user is engaged with the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Partytown for Analytics
&lt;/h3&gt;

&lt;p&gt;Partytown offloads third-party scripts to a web worker, preventing them from blocking the main thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @builder.io/partytown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can improve INP scores by 30–60ms on analytics-heavy pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database and API Query Optimization
&lt;/h2&gt;

&lt;p&gt;Slow server responses hurt LCP even when the client-side is optimized.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Cache for Deduplication
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Multiple components can call this — React deduplicates into one fetch&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connection Pooling
&lt;/h3&gt;

&lt;p&gt;Direct database connections don't scale in serverless environments. Use connection pooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PgBouncer&lt;/strong&gt; (PostgreSQL)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prisma Accelerate&lt;/strong&gt; (built-in connection pooling + query cache)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase Session Pooler&lt;/strong&gt; (Supabase users)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Select Only What You Need
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad: fetches entire record including large content field&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Good: only fetch what the listing page needs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Measuring and Monitoring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Local Testing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
npm start
&lt;span class="c"&gt;# Lighthouse in Chrome DevTools → Performance tab&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test in production mode. Development mode is intentionally slower.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Monitoring
&lt;/h3&gt;

&lt;p&gt;Google PageSpeed only gives you a lab measurement. Real User Monitoring (RUM) shows how your actual visitors experience the site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vercel Analytics&lt;/strong&gt; — built-in Core Web Vitals per URL for Vercel-hosted sites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; → Core Web Vitals report&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry Performance&lt;/strong&gt; — detailed transaction tracing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance Budget
&lt;/h3&gt;

&lt;p&gt;Set a performance budget and enforce it in CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"assert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"assertions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"categories:performance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"minScore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.90&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"first-contentful-paint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"warn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"maxNumericValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"largest-contentful-paint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"maxNumericValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Wins Checklist
&lt;/h2&gt;

&lt;p&gt;Before deep optimization, check these quick wins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All above-fold images use &lt;code&gt;priority&lt;/code&gt; prop&lt;/li&gt;
&lt;li&gt;All images have explicit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; or use &lt;code&gt;fill&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;next/font&lt;/code&gt; instead of Google Fonts &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Heavy components (charts, editors) are lazy loaded with &lt;code&gt;dynamic()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Third-party scripts use appropriate &lt;code&gt;strategy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;next.config.ts&lt;/code&gt; enables AVIF/WebP formats&lt;/li&gt;
&lt;li&gt;Database queries use &lt;code&gt;select&lt;/code&gt; to fetch only needed fields&lt;/li&gt;
&lt;li&gt;Static pages use &lt;code&gt;generateStaticParams&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;"use client"&lt;/code&gt; on components that don't need it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your Next.js site is underperforming and you need expert optimization, &lt;a href="https://www.codexomation.com/contact" rel="noopener noreferrer"&gt;reach out to our team&lt;/a&gt; — we audit and optimize Next.js applications for both performance and SEO as a standalone service.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What Actually Breaks When You Put AI Agents In Front Of Real Customers</title>
      <dc:creator>Codexomation</dc:creator>
      <pubDate>Wed, 26 Aug 2026 00:01:57 +0000</pubDate>
      <link>https://dev.to/codexomation/what-actually-breaks-when-you-put-ai-agents-in-front-of-real-customers-5b2j</link>
      <guid>https://dev.to/codexomation/what-actually-breaks-when-you-put-ai-agents-in-front-of-real-customers-5b2j</guid>
      <description>&lt;p&gt;I have spent the last year building AI automation systems for small businesses. Chatbots, multi agent workflows, the kind of stuff that looks great in a demo and then meets an actual customer who types "idk just fix it" and breaks everything.&lt;/p&gt;

&lt;p&gt;Most articles about AI agents talk about architecture. LangGraph vs CrewAI, which vector store to use, how to chain prompts. That stuff matters, but it is not what actually keeps these systems alive once real money and real users are involved. Here is what I wish someone had told me before I shipped the first one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo lies to you
&lt;/h2&gt;

&lt;p&gt;Every agent demo works because you, the builder, know how to talk to it. You phrase things clearly. You do not typo. You do not ask three questions at once. You do not go silent for ten minutes then come back and say "wait what were we talking about."&lt;/p&gt;

&lt;p&gt;Real users do all of that constantly. The single biggest gap between a working prototype and a working product is handling the messy, half formed, contradictory way people actually type when they are in a hurry or annoyed. If you have not tested your agent with genuinely bad input, you have not tested it.&lt;/p&gt;

&lt;p&gt;What helped: I started keeping a running file of every weird input a real user sent that confused the agent. Once you have fifty of these, patterns show up fast, and you can build handling for the actual failure modes instead of the ones you imagined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Silent failures are worse than loud ones
&lt;/h2&gt;

&lt;p&gt;Early on I built a workflow automation that pulled data from a CRM, ran it through a couple of AI steps, then pushed it into an email tool. When one step failed, the whole thing just quietly stopped. No error, no log anyone checked, nothing. The client found out three days later when they noticed no follow up emails had gone out.&lt;/p&gt;

&lt;p&gt;Now every multi step agent pipeline I build has to answer one question before it ships: when this breaks, who finds out, and how fast? Not if it breaks. When. If the answer is "eventually, by accident," that is not done yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the agent a way to say "I don't know"
&lt;/h2&gt;

&lt;p&gt;This sounds obvious but it is the thing teams skip because it is unglamorous. An agent that confidently makes something up is far more dangerous than one that says "I am not sure, let me get a human." I have seen support bots invent refund policies that did not exist because nobody explicitly told the model it was allowed to punt.&lt;/p&gt;

&lt;p&gt;Building the punt path is not a fallback you bolt on later. It needs to be a first class part of the design, with its own testing, same as the happy path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost creeps up on you fast
&lt;/h2&gt;

&lt;p&gt;A single agent call is cheap. A multi agent system where three or four models talk to each other, sometimes in loops, adds up in ways that are easy to miss until the bill shows up. I had a workflow where an agent would occasionally get stuck re checking its own output in a loop because of a badly worded stop condition. Nobody noticed for two weeks because each individual call was pennies.&lt;/p&gt;

&lt;p&gt;Now I put hard caps on every loop and log every model call with a request id, so if something runs away, I can see it in the dashboard instead of the invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clients do not want "AI." They want the annoying task gone
&lt;/h2&gt;

&lt;p&gt;This one changed how I sell and build entirely. Nobody wakes up excited about a multi agent system. They wake up annoyed that someone on their team spends four hours a week manually copying leads between two tools. The AI part is the how, not the what. The moment I stopped leading with the tech and started leading with the specific task disappearing, projects got easier to scope and easier to keep alive after launch, because success was measured by "does this task still need a human" instead of "is the AI impressive."&lt;/p&gt;

&lt;h2&gt;
  
  
  The part nobody tells you: maintenance is the real job
&lt;/h2&gt;

&lt;p&gt;Shipping the first version is maybe 30 percent of the actual work. APIs change. The model provider quietly updates behavior. Your client's CRM adds a new required field and your integration breaks at 2am. Agent based systems touch more moving parts than a normal app, so they break in more places, and the person who has to own that is usually whoever built it, not whoever bought it.&lt;/p&gt;

&lt;p&gt;If you are freelancing or running a small shop building these systems, price the maintenance in from day one. It is not optional work you might get lucky and skip.&lt;/p&gt;

&lt;p&gt;None of this is meant to talk anyone out of building with AI agents. They genuinely solve real problems when built with the failure modes in mind instead of bolted on after something breaks in production. I just wish more of what I read before starting was about the boring, unglamorous stuff instead of the architecture diagrams.&lt;/p&gt;

&lt;p&gt;If you are building something similar, I would love to hear what broke for you first. It is almost never the thing you expected.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
