<?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>Forem: CodeScoop.dev</title>
    <description>The latest articles on Forem by CodeScoop.dev (@codescoop).</description>
    <link>https://forem.com/codescoop</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.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2578%2F79cddd4e-7cf7-4c07-b40c-fe749dbd00a6.png</url>
      <title>Forem: CodeScoop.dev</title>
      <link>https://forem.com/codescoop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/codescoop"/>
    <language>en</language>
    <item>
      <title>Frontend Performance That Actually Moves the Needle</title>
      <dc:creator>Yogesh Yadav</dc:creator>
      <pubDate>Thu, 16 Apr 2026 20:01:05 +0000</pubDate>
      <link>https://forem.com/codescoop/frontend-performance-that-actually-moves-the-needle-41b7</link>
      <guid>https://forem.com/codescoop/frontend-performance-that-actually-moves-the-needle-41b7</guid>
      <description>&lt;p&gt;In this article we'll cover why Lighthouse scores alone don't tell the full story, what metrics actually matter at scale, how real user monitoring changes the way you think about performance, and the optimizations that have the most impact on platforms serving millions of users.&lt;/p&gt;

&lt;p&gt;Lighthouse is a great tool. I'm not here to tell you to ignore it. But I've seen teams chase a perfect Lighthouse score while their real users were experiencing 4-second load times on mid-range android devices with a 4G connection.&lt;/p&gt;

&lt;p&gt;The score looked great. The experience wasn't.&lt;/p&gt;

&lt;p&gt;When you're building for 10 million users, performance stops being about a number in a report. It becomes about real people on real devices with real network conditions. And the gap between a lab score and what your users actually feel is wider than most developers realize.&lt;/p&gt;

&lt;p&gt;This article is about closing that gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lighthouse Scores Are Lab Data, Not Reality
&lt;/h2&gt;

&lt;p&gt;Lighthouse runs in a controlled environment. Throttled CPU, simulated network, a clean browser with no extensions, no cached data, no background tabs. That's not how your users browse.&lt;/p&gt;

&lt;p&gt;Your users are on a 3-year-old phone with 15 browser tabs open, on a train with patchy network, while your JavaScript is fighting with a background app for CPU time.&lt;/p&gt;

&lt;p&gt;This is why a 90+ Lighthouse score can still result in a poor user experience. The lab doesn't lie, but it only tells you part of the truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lab data:&lt;/strong&gt; what Lighthouse gives you - is useful for catching regressions and tracking trends over time. But it should never be your only signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Field data:&lt;/strong&gt; what your real users experience - is where performance work actually pays off.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Metrics That Actually Matter at Scale
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Web Vitals
&lt;/h3&gt;

&lt;p&gt;Google's Core Web Vitals are the closest thing we have to a standardized set of user-centric performance metrics. Three of them matter most:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LCP - Largest Contentful Paint:&lt;/strong&gt; How long does it take for the largest visible element to render? For most platforms this is a hero image, a video thumbnail or a headline. This is what the user perceives as "the page loaded."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Target: under 2.5 seconds.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;INP - Interaction to Next Paint:&lt;/strong&gt; How quickly does the page respond after a user interaction? Click a button, tap a menu, submit a form - how long before the page visually responds? This replaced FID (First Input Delay) in 2024 and is a much better measure of real interactivity.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Target: under 200 milliseconds.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLS - Cumulative Layout Shift&lt;/strong&gt; How much does the page jump around while loading? Ads loading late, images without dimensions, fonts swapping - these all contribute to CLS. On a content-heavy platform this can quietly destroy the user experience.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Target: under 0.1.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These three metrics directly impact SEO ranking and user retention. At scale, a 0.1 improvement in CLS or a 500ms reduction in LCP translates to measurable engagement and conversion improvements.&lt;/p&gt;

&lt;h3&gt;
  
  
  TTFB - Time to First Byte
&lt;/h3&gt;

&lt;p&gt;Before the browser can render anything, it needs a response from the server. TTFB measures that wait time. High TTFB usually points to server-side issues - slow API responses, no CDN or unoptimized server rendering.&lt;/p&gt;

&lt;p&gt;On platforms with a global audience, CDN configuration alone can cut TTFB from 800ms to under 100ms for a significant portion of your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  TTI - Time to Interactive
&lt;/h3&gt;

&lt;p&gt;When can the user actually use the page? Not just see it, but interact with it without the UI freezing. This is where JavaScript bundle size and execution time have the most direct impact.&lt;/p&gt;

&lt;p&gt;A page that looks loaded but isn't responding to clicks is one of the most frustrating experiences a user can have.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real User Monitoring - The Signal You Can't Ignore
&lt;/h2&gt;

&lt;p&gt;If you're only running Lighthouse, you're flying partially blind. Real User Monitoring (RUM) captures performance data from actual user sessions and sends it back to you.&lt;/p&gt;

&lt;p&gt;The difference is significant. With RUM you can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How performance varies by device type, browser and geography&lt;/li&gt;
&lt;li&gt;Which pages have the worst real-world LCP or INP&lt;/li&gt;
&lt;li&gt;How performance degrades over time as your codebase grows&lt;/li&gt;
&lt;li&gt;What percentage of your users are experiencing poor performance right now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools like Datadog RUM, SpeedCurve, Mux Data or even the free Chrome User Experience Report (CrUX) give you this visibility.&lt;/p&gt;

&lt;p&gt;On a platform serving millions of users, even if 5% of your users are experiencing poor performance, that's 500,000 people having a bad time. RUM makes that visible. Lighthouse doesn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Optimizations That Actually Move the Needle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. JavaScript Bundle Size
&lt;/h3&gt;

&lt;p&gt;This is almost always the biggest lever. JavaScript is the most expensive resource on the web - it has to be downloaded, parsed, and executed before it does anything useful.&lt;/p&gt;

&lt;p&gt;Code splitting is non-negotiable at scale. Every route should load only the JavaScript it needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of importing everything upfront&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;HeavyComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./HeavyComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Load it only when needed&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HeavyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&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="s1"&gt;./HeavyComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Audit your bundle regularly. Tools like &lt;code&gt;webpack-bundle-analyzer&lt;/code&gt; or &lt;code&gt;vite-bundle-visualizer&lt;/code&gt; will show you exactly what's in your bundle and where the weight is coming from. You will almost always find something surprising.&lt;/p&gt;

&lt;p&gt;Third-party scripts are usually the worst offenders. Analytics, chat widgets, ad scripts - these are often loaded synchronously and block rendering. Load them async or defer them entirely until after the page is interactive.&lt;/p&gt;

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

&lt;p&gt;Images are the largest assets on most pages. Getting this wrong has a direct impact on LCP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use modern formats. WebP is widely supported and significantly smaller than JPEG or PNG. AVIF is even better where supported.&lt;/li&gt;
&lt;li&gt;Always set explicit width and height on images. This prevents layout shift and helps the browser allocate space before the image loads.&lt;/li&gt;
&lt;li&gt;Use lazy loading for images below the fold.&lt;/li&gt;
&lt;li&gt;Serve appropriately sized images. Don't serve a 2000px wide image to a 400px wide mobile screen.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"thumbnail.webp"&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"225"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Video thumbnail"&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;For a platform with a large content library, image optimization alone can reduce page weight by 40–60%.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Critical Rendering Path
&lt;/h3&gt;

&lt;p&gt;The browser has to download your HTML, parse it, discover CSS and JavaScript, download those, parse them and then render the page. Every step in that chain is an opportunity to either speed things up or slow things down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inline critical CSS - the styles needed to render above-the-fold content - directly in the HTML. This eliminates a render-blocking network request for the initial view.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Preload key resources the browser won't discover until late in the parsing process.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/fonts/main.woff2"&lt;/span&gt; &lt;span class="na"&gt;crossorigin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/hero.webp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Defer non-critical JavaScript. If a script doesn't need to run before the page is interactive, it shouldn't block rendering.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Caching Strategy
&lt;/h3&gt;

&lt;p&gt;I covered this in depth in the previous article in this series, but it's worth mentioning here because caching is one of the highest-impact performance optimizations available to you.&lt;/p&gt;

&lt;p&gt;Repeat visitors on a well-cached platform can load pages almost entirely from cache. No network requests for static assets, no server round trips for unchanged resources. The performance improvement for returning users is dramatic.&lt;/p&gt;

&lt;p&gt;If you haven't read the &lt;a href="https://dev.to/codescoop/frontend-caching-done-right-2lem"&gt;caching article&lt;/a&gt; yet, it's worth going back to.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Reducing Main Thread Work
&lt;/h3&gt;

&lt;p&gt;INP and TTI both suffer when the main thread is busy. JavaScript execution, long tasks, layout recalculations - these all compete for the same thread that handles user interactions.&lt;/p&gt;

&lt;p&gt;A few things that help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Break up long tasks. Any task that takes more than 50ms can cause noticeable jank. Use setTimeout or scheduler.postTask to yield control back to the browser between chunks of work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid layout thrashing. Reading and writing to the DOM in alternating calls forces the browser to recalculate layout repeatedly. Batch your reads and writes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move heavy computation off the main thread with Web Workers.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Yielding to the browser between heavy tasks&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;processLargeDataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Performance Budgets - Making It Stick
&lt;/h2&gt;

&lt;p&gt;One of the hardest parts of performance work at scale is keeping improvements from regressing over time. A performance budget solves this.&lt;/p&gt;

&lt;p&gt;A performance budget sets explicit limits on metrics like bundle size, LCP or TTI. If a pull request would push you over the budget, it fails the build.&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;"resourceSizes"&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="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&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="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&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="nl"&gt;"timings"&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="nl"&gt;"metric"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1500&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="nl"&gt;"metric"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"interactive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3500&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;p&gt;This keeps performance on everyone's radar, not just the engineer who cared enough to optimize it once.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Scale Actually Teaches You About Performance
&lt;/h2&gt;

&lt;p&gt;Here's what I've learned from working on platforms at this size that you don't find in most performance guides:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device distribution matters more than you think.&lt;/strong&gt; Your development machine is not representative of your users. Profile on a mid-range Android device and you will find issues you never knew existed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Geography matters.&lt;/strong&gt; A platform with a global audience needs a CDN strategy, not just a fast server in one region. Network latency from a distant origin server can add seconds to TTFB for users in certain regions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance degrades gradually.&lt;/strong&gt; Nobody ships a slow app intentionally. It gets slow one dependency, one feature, one third-party script at a time. Without a budget and regular monitoring, you won't notice until users are already complaining.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 80/20 rule applies.&lt;/strong&gt; A small number of pages usually account for the majority of your traffic. Find those pages, measure them obsessively and optimize them first. That's where your performance work will have the most impact.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Lighthouse is a tool, not a goal. A green score means you've done the basics right. It doesn't mean your users are having a fast experience.&lt;/p&gt;

&lt;p&gt;The teams that get performance right at scale are the ones who measure what their real users experience, set budgets to prevent regression and focus their effort on the optimizations that actually move the needle for their specific platform and audience.&lt;/p&gt;

&lt;p&gt;Start with RUM. Find where your real users are struggling. Fix those things first.&lt;/p&gt;

&lt;p&gt;The Lighthouse score will follow.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have thoughts or questions on frontend performance? Drop them in the comments, always happy to discuss.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is part of the &lt;strong&gt;Frontend at Scale&lt;/strong&gt; series.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Frontend Caching Done Right</title>
      <dc:creator>Yogesh Yadav</dc:creator>
      <pubDate>Sun, 05 Apr 2026 06:39:19 +0000</pubDate>
      <link>https://forem.com/codescoop/frontend-caching-done-right-2lem</link>
      <guid>https://forem.com/codescoop/frontend-caching-done-right-2lem</guid>
      <description>&lt;p&gt;In this article we’ll cover how the browser cache and HTTP headers work, when and how to use stale-while-revalidate, how service workers give you programmatic control over caching, what you should never cache, and how cache invalidation works in practice. All of it from the perspective of building for platforms that can’t afford to get this wrong.&lt;/p&gt;

&lt;p&gt;Caching is one of those topics that every frontend developer thinks they understand, until they’re staring at a production issue where users are getting stale data, or worse, the server is getting hammered because nothing is being cached at all.&lt;/p&gt;

&lt;p&gt;I’ve worked on platforms handling more than 10 million active users. And I can tell you, caching stops being a “nice to have” the moment your scale starts growing. It becomes the difference between a platform that feels fast and one that quietly falls apart under load.&lt;/p&gt;

&lt;p&gt;This article is everything I’ve learned about frontend caching, written the way I wish someone had explained it to me early in my career.&lt;/p&gt;




&lt;h2&gt;
  
  
  First, Understand What You Are Actually Caching
&lt;/h2&gt;

&lt;p&gt;Before you touch a single HTTP header or write a line of service worker code, ask yourself one question.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the cost of serving stale data here?
&lt;/h3&gt;

&lt;p&gt;That question determines everything. Because caching is always a tradeoff between freshness and performance. The mistake most developers make is treating all resources the same way. They’re not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s how I think about it:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static assets&lt;/strong&gt; (JS bundles, CSS, fonts, images) - these can be cached aggressively, sometimes forever, if you version them correctly.&lt;br&gt;
&lt;strong&gt;API responses&lt;/strong&gt; - depends entirely on how often the data changes and how much it matters if the user sees something slightly outdated.&lt;br&gt;
&lt;strong&gt;HTML documents&lt;/strong&gt; - usually should not be cached aggressively, especially for authenticated apps.&lt;br&gt;
&lt;strong&gt;User-specific data&lt;/strong&gt; - almost never cache this without thinking carefully.&lt;/p&gt;

&lt;p&gt;Get this mental model right first. Everything else follows from it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Browser Cache and HTTP Headers
&lt;/h2&gt;

&lt;p&gt;The browser cache is your first and most powerful caching layer. It lives between the user and your server, and it’s controlled entirely through HTTP response headers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cache-Control
&lt;/h3&gt;

&lt;p&gt;This is the header you’ll use the most. Here’s what the key directives actually mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: max-age=31536000, immutablety
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;max-age&lt;/code&gt; tells the browser how many seconds to keep this resource before considering it stale. &lt;code&gt;immutable&lt;/code&gt; tells the browser not to bother revalidating it even on a hard refresh, because the content will never change.&lt;/p&gt;

&lt;p&gt;Use this combination for versioned static assets, your JS bundles, CSS files, and images that have a content hash in the filename. Something like &lt;code&gt;main.a3f9c2.js&lt;/code&gt;. The hash changes every build, so the URL changes, so you never serve stale code. Cache it forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: no-cache
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite the name, this does not mean “don’t cache.” It means “cache it, but check with the server every time before using it.” The server can respond with a &lt;code&gt;304 Not Modified&lt;/code&gt; and the browser uses the cached version. No full download needed.&lt;/p&gt;

&lt;p&gt;Use this for your HTML documents. You want the browser to always check if there’s a new version, but still benefit from caching when nothing has changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: no-store
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This actually means “don’t cache.” Nothing is stored anywhere. Use this for sensitive data, authentication responses, anything you never want sitting in a cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  ETag and Last-Modified
&lt;/h3&gt;

&lt;p&gt;These work alongside &lt;code&gt;Cache-Control&lt;/code&gt; for revalidation. When the browser asks "has this changed?", the server uses these to answer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;ETag: "abc123"
Last-Modified: Mon, 01 Jan 2024 00:00:00 GMT
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser sends back &lt;code&gt;If-None-Match: "abc123"&lt;/code&gt; or &lt;code&gt;If-Modified-Since&lt;/code&gt; on the next request. If nothing changed, the server returns 304 and saves the bandwidth of sending the full response again.&lt;/p&gt;

&lt;p&gt;At scale, these small savings add up to a significant reduction in server load.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stale-While-Revalidate
&lt;/h2&gt;

&lt;p&gt;This is one of the most underused caching strategies I’ve seen in frontend codebases, and it’s genuinely powerful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: max-age=60, stale-while-revalidate=300
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what this does. For the first 60 seconds, serve from cache, no questions asked. Between 60 and 300 seconds, serve the stale cached version immediately, but kick off a background request to revalidate it. After 300 seconds, it’s stale and must be revalidated before serving.&lt;/p&gt;

&lt;p&gt;The user gets an instant response. The cache gets updated in the background. No loading spinner, no waiting.&lt;/p&gt;

&lt;p&gt;This pattern is perfect for data that changes occasionally but doesn’t need to be real-time. Think navigation menus, configuration data, content that updates a few times a day. The user always gets a fast experience and the data stays reasonably fresh.&lt;/p&gt;

&lt;p&gt;You’ll also recognize this pattern from TanStack Query’s &lt;code&gt;staleTime&lt;/code&gt; and &lt;code&gt;gcTime&lt;/code&gt; configuration. The underlying idea is exactly the same, just applied at the JavaScript layer instead of the HTTP layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Service Workers - The Programmable Cache
&lt;/h2&gt;

&lt;p&gt;HTTP headers give you declarative control over caching. Service workers give you programmatic control. That’s a significant difference.&lt;/p&gt;

&lt;p&gt;A service worker sits between your app and the network, intercepting every request. You decide what happens with each one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&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;event&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cachedResponse&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedResponse&lt;/span&gt;&lt;span class="p"&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;cachedResponse&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple cache-first strategy. Check the cache first, fall back to the network if nothing is found. For a platform serving millions of users, this means repeat visitors often never hit your server for static assets at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching Strategies with Service Workers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cache First&lt;/strong&gt; - Serve from cache, fall back to network. Best for static assets that rarely change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network First&lt;/strong&gt; - Try the network, fall back to cache if offline. Best for API data where freshness matters but offline support is needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stale While Revalidate&lt;/strong&gt; - Serve from cache immediately, update cache in background. Best for non-critical content where speed matters more than freshness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache Only&lt;/strong&gt; - Only serve from cache. Useful for assets you’ve pre-cached during install.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Only&lt;/strong&gt; - Always go to network. For requests that should never be cached, like analytics or payment endpoints.&lt;/p&gt;

&lt;p&gt;Pick your strategy per resource type, not globally. A single strategy for everything is almost always the wrong call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-caching vs Runtime Caching
&lt;/h3&gt;

&lt;p&gt;Pre-caching happens when the service worker installs. You explicitly list assets to cache upfront.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;install&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;event&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&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="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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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="s1"&gt;/styles/main.css&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="s1"&gt;/scripts/main.js&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;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;Runtime caching happens dynamically as requests come in. You cache responses as they’re fetched, so frequently accessed resources end up in cache naturally over time.&lt;/p&gt;

&lt;p&gt;For most platforms, you want both. Pre-cache your critical shell, runtime cache everything else.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Not to Cache
&lt;/h2&gt;

&lt;p&gt;This is the part that trips people up. Caching the wrong things causes bugs that are genuinely hard to debug in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never aggressively cache:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication tokens or session data&lt;/li&gt;
&lt;li&gt;Payment and transaction endpoints&lt;/li&gt;
&lt;li&gt;User-specific personalization data&lt;/li&gt;
&lt;li&gt;Anything that changes per user or per session&lt;/li&gt;
&lt;li&gt;A/B test configurations if they need to be real-time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve seen teams cache API responses that included user-specific entitlements. The result was users seeing content they shouldn’t have access to, or not seeing content they’d just purchased. At scale, that’s not just a bug. It’s a trust problem.&lt;/p&gt;

&lt;p&gt;When in doubt, don’t cache it, or use &lt;code&gt;no-cache&lt;/code&gt; so at least revalidation happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cache Invalidation - The Hard Part
&lt;/h2&gt;

&lt;p&gt;There’s a famous saying in computer science: there are only two hard things, naming things and cache invalidation.&lt;/p&gt;

&lt;p&gt;It’s funny because it’s true.&lt;/p&gt;

&lt;p&gt;For static assets, content-hashed filenames solve this completely. New deploy, new hash, new URL, new cache entry. Old one expires naturally.&lt;/p&gt;

&lt;p&gt;For API responses and service worker caches, you need a versioning strategy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CACHE_VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;activate&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;event&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cacheNames&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;cacheNames&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&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;gt;&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;CACHE_VERSION&lt;/span&gt;&lt;span class="p"&gt;)&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;name&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;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&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="p"&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;Every time you deploy, bump the cache version. The activate event cleans up old caches. Users get fresh data on their next visit without you having to manually purge anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Caching at Scale - What Actually Changes
&lt;/h2&gt;

&lt;p&gt;When you’re building for 10 million users, the fundamentals don’t change. But the consequences of getting it wrong are amplified significantly.&lt;/p&gt;

&lt;p&gt;A few things I’ve learned from operating at that scale:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure before you optimize.&lt;/strong&gt; Use Chrome DevTools, Lighthouse, and your RUM (Real User Monitoring) data to understand where your actual cache hit rates are. Don’t guess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CDN caching and browser caching are different layers.&lt;/strong&gt; Your CDN has its own cache headers, often separate from what the browser sees. Understand both. Misconfiguring your CDN can mean millions of users bypassing the browser cache entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache stampedes are real.&lt;/strong&gt; When a popular cached resource expires simultaneously for millions of users, they all hit your server at once. Stale-while-revalidate and jittered expiry times help prevent this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor your cache hit ratio.&lt;/strong&gt; If it’s low, you’re leaving performance on the table. If it’s too high and you’re seeing stale data complaints, your TTLs are too aggressive.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Caching is not a set-it-and-forget-it feature. It’s an ongoing engineering decision that touches performance, correctness and user experience all at once.&lt;/p&gt;

&lt;p&gt;Start with HTTP headers and get those right. Layer in stale-while-revalidate for the right resources. Add service workers when you need offline support or more granular control. And always think about invalidation before you think about caching.&lt;/p&gt;

&lt;p&gt;The developers who get this right aren’t the ones who know the most cache directives. They’re the ones who ask the right question first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the cost of serving stale data here?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Answer that honestly for every resource, and the rest follows.&lt;/p&gt;




&lt;p&gt;Have thoughts or questions on frontend caching? Drop them in the comments, always happy to discuss.&lt;/p&gt;

&lt;p&gt;This article is part of the &lt;strong&gt;Frontend at Scale&lt;/strong&gt; series.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>caching</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Explore the lexical Environment &amp; Environment Record in Javascript 2021</title>
      <dc:creator>Yogesh Yadav</dc:creator>
      <pubDate>Wed, 17 Aug 2022 07:23:00 +0000</pubDate>
      <link>https://forem.com/codescoop/what-has-changed-in-lexical-environment-as-per-ecmascript-2021-2bjb</link>
      <guid>https://forem.com/codescoop/what-has-changed-in-lexical-environment-as-per-ecmascript-2021-2bjb</guid>
      <description>&lt;p&gt;Let's first understand the &lt;code&gt;Lexical Environment&lt;/code&gt; &amp;amp; &lt;code&gt;Environment Record&lt;/code&gt; as per different versions of ECMAScript Specification.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://262.ecma-international.org/6.0/" rel="noopener noreferrer"&gt;&lt;strong&gt;ES2015&lt;/strong&gt;&lt;/a&gt; till &lt;a href="https://262.ecma-international.org/11.0/" rel="noopener noreferrer"&gt;&lt;strong&gt;ES2020&lt;/strong&gt;&lt;/a&gt; Specification:-&lt;/p&gt;

&lt;h2&gt;Lexical Environment: &lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A lexical environment is a &lt;strong&gt;specification type&lt;/strong&gt; used to define the association of Identifiers to specific variables and functions, based upon the lexical nesting structure of your code.&lt;/li&gt;
&lt;li&gt;A lexical environment consists of two components:

&lt;ol&gt;
&lt;li&gt;
&lt;h4&gt;Environment Record&lt;/h4&gt; It records the &lt;strong&gt;identifier bindings&lt;/strong&gt; that are created within the scope of its associated Lexical Environment. It is referred to as the Lexical Environment's EnvironmentRecord.&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;Outer Reference&lt;/h4&gt; A reference to outer environment (null in the global environment).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A conceptual view using pseudo-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;executioncontext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;environmentRecord&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// storage&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;identifier&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;value&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;identifier&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// reference to the parent environment&lt;/span&gt;
    &lt;span class="nl"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; - The &lt;code&gt;[[Environment]]&lt;/code&gt; created inside Execution Context is of &lt;code&gt;type&lt;/code&gt; &lt;strong&gt;Lexical Environment&lt;/strong&gt; &lt;br&gt;
 &lt;a href="https://262.ecma-international.org/11.0/#sec-ecmascript-function-objects" rel="noopener noreferrer"&gt;[refer ES2020]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foeq4770whr2mksmrwt0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foeq4770whr2mksmrwt0s.png" alt="Lexical Environment in Global Scope" width="800" height="418"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://262.ecma-international.org/12.0/" rel="noopener noreferrer"&gt;&lt;strong&gt;12th Edition ECMAScript2021&lt;/strong&gt;&lt;/a&gt; Specification:&lt;/p&gt;

&lt;h2&gt;Environment Record &lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Environment Record is a &lt;strong&gt;specification type&lt;/strong&gt; used to define the association of Identifiers to specific variables and functions, based upon the lexical nesting structure of your code.&lt;/li&gt;
&lt;li&gt;Every Environment Record has one component:

&lt;ol&gt;
&lt;li&gt;
&lt;h4&gt;Outer Reference&lt;/h4&gt; An &lt;code&gt;[[OuterEnv]]&lt;/code&gt; field, which is either null or a reference to an outer Environment Record.
A conceptual view using pseudo-code:
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;executioncontext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// storage&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;identifier&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;value&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;identifier&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// reference to the parent environment&lt;/span&gt;
    &lt;span class="na"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; - The &lt;code&gt;[[Environment]]&lt;/code&gt; created inside Execution Context is of &lt;code&gt;type&lt;/code&gt; &lt;strong&gt;Environment Record&lt;/strong&gt; &lt;a href="https://262.ecma-international.org/12.0/#sec-ecmascript-function-objects" rel="noopener noreferrer"&gt;[refer ES2021]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06g8v67qzlgcds5i22fk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06g8v67qzlgcds5i22fk.png" alt="Environment Record in Global Scope" width="800" height="399"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Let's also understand the &lt;code&gt;Structure of execution context&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt; Execution Context: &lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An execution context is a specification device that is used to track the runtime evaluation of the code.&lt;/li&gt;
&lt;li&gt;To keeps the track of execution progress of its associated code, it needs various &lt;strong&gt;state components&lt;/strong&gt; like &lt;code&gt;LexicalEnvironment&lt;/code&gt;, &lt;code&gt;VariableEnvironment&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In pseudo-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ExecutionContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;VariableEnvironment&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="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;LexicalEnvironment&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="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// other components&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;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Till ES2020&lt;/th&gt;
&lt;th&gt;From ES2021&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;- The &lt;code&gt;LexicalEnvironment component&lt;/code&gt; and &lt;code&gt;VariableEnvironment component&lt;/code&gt; of an execution context are always &lt;strong&gt;Lexical Environments&lt;/strong&gt; &lt;a href="https://262.ecma-international.org/11.0/#table-23" rel="noopener noreferrer"&gt;[refer ES2020]&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;- The &lt;code&gt;LexicalEnvironment component&lt;/code&gt; and &lt;code&gt;VariableEnvironment&lt;/code&gt; components of an execution context are always &lt;strong&gt;Environment Records&lt;/strong&gt; &lt;a href="https://262.ecma-international.org/12.0/#table-23" rel="noopener noreferrer"&gt;[refer ES2021]&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt; Summary &lt;/h2&gt;

&lt;p&gt;Let's have a quick recap of all the steps we perform in the above code snippet.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In ECMAScript2021, the &lt;code&gt;[[environment]]&lt;/code&gt; which is created inside the execution context is of &lt;code&gt;type&lt;/code&gt; &lt;strong&gt;Environment Record&lt;/strong&gt; instead of Lexical Environment.&lt;/li&gt;
&lt;li&gt;So, The &lt;code&gt;LexicalEnvironment component&lt;/code&gt; and &lt;code&gt;VariableEnvironment components&lt;/code&gt; of an execution context are always &lt;strong&gt;Environment Records&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Wrap Up!!&lt;/h2&gt;

&lt;p&gt;Thank you for your time!! Let's connect to learn and grow together.&lt;br&gt;
&lt;a href="https://github.com/deltanode" rel="noopener noreferrer"&gt;Github&lt;/a&gt; &lt;a href="https://twitter.com/yogesh_yadv" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
