Fix 'Reduce Unused JavaScript' in Lighthouse

Find and remove unused JavaScript to improve your Core Web Vitals

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-03

'Reduce unused JavaScript' in short

Whenever you get the 'reduce unused JavaScript' warning in Lighthouse, it means that too much JavaScript has been loaded too early during page load.

Unused JavaScript competes for network resources and blocks the main thread. This slows down the Core Web Vitals, especially the Largest Contentful Paint (LCP) and the Interaction to Next Paint (INP).

Fix this issue by removing dead code, tree shaking your bundles, code splitting your routes, and deferring code that is not immediately needed.

Website Speed Audit

What is the 'reduce unused JavaScript' Lighthouse warning?

Last reviewed by Arjen Karel on March 2026

Lighthouse flags every JavaScript file with more than 20 KiB of unused code. If you see this warning, your page is downloading and executing JavaScript that it does not need for the current page load.

This warning directly impacts your Lighthouse performance score. But more importantly, unused JavaScript hurts your real users. According to the 2025 Web Almanac, the median mobile page ships 646 KB of JavaScript, and 251 KB of that goes unused on the page where it loads. At the 90th percentile, that number climbs to 931 KB of wasted JavaScript.

Meanwhile, mobile Total Blocking Time increased 58% year over year to a median of 1,916 ms according to the 2025 Web Almanac Performance chapter. JavaScript payloads are growing faster than devices are getting faster. Across sites monitored by CoreDash, origins that keep their unused JavaScript below 100 KB score "good" on INP 93% of the time, compared to 64% for origins exceeding 400 KB.

What causes unused JavaScript?

Unused JavaScript can have many causes. The most common ones are:

  • Too many plugins in your CMS.
  • Dead code that is no longer used by the current website.
  • Poorly written scripts with unnecessary checks and branches.
  • Unrestricted tag manager access, where marketing teams add tags and forget to remove them.
  • Unnecessary imports: pulling in an entire library when you only use one function.
  • Code that runs on every page but is only needed on specific routes.
  • Scripts loaded immediately that could have been loaded right before use.

How does unused JavaScript affect the Core Web Vitals?

Unused JavaScript hits your performance in two ways:

  • Network contention. Every JavaScript file needs to be downloaded. These requests compete for bandwidth with your LCP image, your fonts, and your CSS. On a mobile connection, this delay can push your Largest Contentful Paint well past the 2.5 second threshold.
  • Main thread blocking. The browser has to parse, compile, and execute all that JavaScript. While it does, it cannot respond to user input or continue rendering the page. This directly impacts both LCP and INP.

Keep in mind that a Lighthouse score is not a Core Web Vitals score. The Core Web Vitals are measured with field data from real users (CrUX). Lighthouse is a diagnostic tool that helps you find problems, but your real performance is what your visitors actually experience. You can verify your field performance with Real User Monitoring.

How to find unused JavaScript

There are three ways to identify unused JavaScript on your page:

1. Read the Lighthouse audit

Lighthouse lists every JavaScript file that has more than 20 KiB of unused code. It shows the total bytes, the unused bytes, and the potential savings. This is your starting point. Note that Lighthouse 13 (October 2025) moved to an insight-based audit format, but the unused JavaScript check is still there.

2. Use the Chrome Coverage tool

The Coverage tool gives you a line-by-line breakdown of used versus unused code for every JavaScript and CSS file on the page.

Open Chrome DevTools with Ctrl+Shift+I (or Cmd+Option+I on Mac). Then use Ctrl+Shift+P to open the command menu and type coverage. Select Show Coverage, then click the reload button to start instrumenting. After the page loads, you will see every file with its percentage of unused bytes.

Switch to "Per block" coverage mode (dropdown at the top of the panel) for more granular results. Block-level coverage detects unused branches within functions, not just whether a function was called at all.

Click any row to open the file in the Sources panel. Blue lines are used code. Red lines are unused. This tells you exactly which functions and branches were never executed during the page load.

3. Analyze your bundles

If you use a bundler like webpack, Rollup, or Vite, use a bundle analyzer to visualize what is inside your JavaScript files. Tools like webpack-bundle-analyzer and source-map-explorer show a treemap of every module in your bundle, making it obvious when a large library is pulled in for a small feature.

Unused does not always mean unneeded

Keep in mind that "unused" on one page does not mean "unneeded." A script that powers your checkout form shows as 100% unused on your homepage. That does not mean you should delete it. It means you should not load it on the homepage.

This is what code splitting solves: each route loads only the JavaScript it actually needs. If you see large amounts of "unused" JavaScript and your site is a single page application, the fix is almost always better route-level code splitting, not deleting code.

How to fix 'reduce unused JavaScript'

To fix the 'reduce unused JavaScript' warning you first need to trace where the waste is coming from. Lighthouse tells you which scripts have a high amount of unused bytes. Here are 7 ways to reduce it:

  1. Remove unneeded plugins. If you use a CMS like WordPress, the easiest win is removing plugins you do not need or replacing trivial plugins with a few lines of code. Your analytics plugin, social share buttons, and chat widget are common offenders.
  2. Remove dead code. Dead code is code that the current website no longer uses. Schedule a dead code audit at least twice a year. Tools like Knip can automate detection of unused exports and dependencies in JavaScript projects.
  3. Tree shake your bundles. Tree shaking removes unused exports at build time. For it to work, you need ES module syntax (import/export), not CommonJS (require). Add "sideEffects": false to your package.json so your bundler can aggressively remove unused code. Import only what you need:
    // Bad: imports the entire library (70+ KB)
    import _ from 'lodash';
    const result = _.debounce(fn, 300);
    
    // Good: imports only debounce (~1 KB with tree shaking)
    import { debounce } from 'lodash-es';
    const result = debounce(fn, 300);
  4. Code split your routes. Load only the JavaScript each page actually needs. Use dynamic import() to split your bundles by route or by feature:
    // Instead of importing everything upfront:
    import { validateForm } from './formValidation.js';
    
    // Load it only when the user interacts with the form:
    document.querySelector('form').addEventListener('focus', async () => {
      const { validateForm } = await import('./formValidation.js');
      validateForm();
    }, { once: true });

    In React, use React.lazy() with <Suspense> for component-level splitting. In Next.js App Router, React Server Components send zero JavaScript to the client by default. In Vue, use defineAsyncComponent() or dynamic imports in Vue Router.

  5. Clean up your tag manager and restrict access. Tag manager is a common source of unused code, especially when marketing teams add tags without removing old ones. Audit your tag manager container regularly. Every tag that fires on page load adds JavaScript that competes for resources.
  6. Remove unnecessary imports. In React, Vue, and Next.js projects, check your import statements. Are you importing an entire component library when you only use two components? Are you pulling in moment.js (330 KB) when the native Intl API or a 2 KB alternative like dayjs would do?
  7. Defer loading of non-critical scripts. Sometimes you need a script (to submit a form, for example) but you do not need it during page load. Load it when the user actually needs it. A script that loads on interaction instead of on page load is no longer "unused JavaScript" in the Lighthouse audit. See also async vs defer for understanding the difference between the two loading strategies.

When you cannot fully fix it

Sometimes you cannot remove all unused JavaScript. Third-party scripts, A/B testing tools, and ad networks often ship large bundles you have no control over. In that case, minimize their impact:

  • Self-host third-party scripts on your main domain where possible. This avoids the cost of a new DNS lookup and TCP connection for each external domain.
  • Prioritize critical resources. Preload your LCP image and critical fonts so they are not stuck behind JavaScript downloads in the network queue.
  • Defer as much JavaScript as you can. Move non-critical scripts out of the critical rendering path using defer, async, or delayed loading.
  • Use fetchpriority="low" on non-essential script resources to tell the browser they can wait.
  • Monitor your field data. Use Real User Monitoring to verify that your changes actually improved the experience for real users, not just the Lighthouse score.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Search Console flagged your site?

When Google flags your Core Web Vitals you need a clear diagnosis fast. I deliver a prioritized fix list within 48 hours.

Request Urgent Audit
Fix 'Reduce Unused JavaScript' in LighthouseCore Web Vitals Fix 'Reduce Unused JavaScript' in Lighthouse