Back to Blog
Website Optimization5 min readMay 16, 2026

How JavaScript Slows Down Websites

JavaScript is the biggest reason production websites feel slow. Here's how it kills your score and the systematic way to reduce it.

lines of HTML codes
Photo by Florian Olivo on Unsplash
Table of contents

JavaScript is the single biggest reason real-world websites are slow. It's downloaded, parsed, compiled, and executed — all on the user's CPU, which on mobile is roughly 4× slower than on a developer's laptop.

Here's exactly how JavaScript hurts your site and the systematic way to cut it back.

The hidden cost of JavaScript

Bytes vs CPU cost

A 200KB image takes 200KB of bandwidth. That's it. The browser displays it and moves on.

A 200KB JavaScript bundle takes 200KB of bandwidth — plus parse time, compile time, and execution time. On a mid-range Android phone, processing 200KB of JS takes roughly 400ms. On the same phone, processing 1MB takes 2+ seconds.

That's why halving your JS bundle often gives a bigger speed boost than halving your image weight.

Main thread blocking

JavaScript runs on the main thread — the same thread that paints frames and responds to clicks. While JS is executing, the browser can't:

  • Respond to user input (kills your INP)
  • Render new frames
  • Process other tasks

A single 200ms JavaScript task makes the whole page feel laggy.

Render blocking

Synchronous <script> tags block HTML parsing. Until the script downloads and runs, the rest of the page sits unprocessed.

<!-- ❌ Blocks parsing until script downloads + runs -->
<script src="/big.js"></script>

<!-- ✅ Downloads in parallel, runs after parse -->
<script src="/big.js" defer></script>

<!-- ✅ Downloads in parallel, runs ASAP (no order guarantee) -->
<script src="/big.js" async></script>

The five worst JavaScript offenders

1. Tag managers

Google Tag Manager (GTM), Tealium, etc. ship a small loader that pulls in more JavaScript at runtime — often hundreds of KB of analytics, A/B test, and marketing scripts. Each one runs on your main thread.

Fix: Question whether you need GTM at all. If you do, prune the tags you don't actively use, and load GTM with async.

2. Analytics

Google Analytics, Mixpanel, Segment, Heap, FullStory — each adds 30–200KB of JS and event handlers that run on every interaction.

Fix: Pick one. Use server-side analytics if possible (Plausible has both, PostHog has reverse-proxy). Avoid stacking multiple analytics platforms.

3. A/B testing tools

Optimizely, VWO, Google Optimize (RIP) — these are notorious for "flicker" because they delay rendering until the test variant loads. Often 100+ KB of script that blocks paint.

Fix: Run tests server-side or at the edge (Vercel Edge Config, Cloudflare Workers). Avoid client-side A/B test platforms if you can.

4. Chat widgets

Intercom, Drift, HubSpot chat — typically 200–500KB of script and CSS. They almost never need to load before user interaction.

Fix: Lazy-load the widget. Initialize it only when the user clicks a "Chat with us" button.

5. Embedded videos

A YouTube embed pulls in 500KB+ of JS even if the user never plays the video.

Fix: Use a lite-youtube-embed or facade pattern — show a thumbnail and only load the real player on click.

How to cut your JavaScript

Audit what you ship

In Chrome DevTools → Coverage tab → record a page load. You'll see how much of each JS file is actually used on the page. Most sites discover they're shipping 50–70% unused code.

In Lighthouse, the "Reduce unused JavaScript" opportunity tells you the same thing with byte counts.

Replace heavy libraries

HeavyAlternativeSavings
Moment.js (300KB)date-fns or native Intl280+ KB
Lodash (70KB)native ES methods or lodash-es per-method60+ KB
jQuery (90KB)vanilla JS, modern DOM APIs90 KB
Bootstrap JS (60KB)Tailwind + small JS, or no framework60 KB
Axios (15KB)native fetch15 KB

For libraries you do need, import only what you use (tree-shaking):

// ❌ Imports entire library
import _ from "lodash";

// ✅ Imports only what's needed (tree-shaken)
import { debounce } from "lodash-es";

Code-split

Don't ship the JavaScript for every page on every page. Use dynamic imports:

// Loaded only when needed
const Chart = await import("./Chart");

In Next.js, next/dynamic makes this easy. In React, React.lazy does the same.

Defer everything you can

If a script isn't required for first paint, give it defer or async. Run analytics, marketing pixels, and chat scripts after the page is interactive.

Use SSR or SSG

A statically-rendered page can ship far less JavaScript than a fully client-rendered one. Next.js (with SSG or SSR), Astro, and Hugo are examples of frameworks that ship minimal JS by default.

Reduce re-renders

If you're using React/Vue/etc., re-renders are JS work on the main thread. Use:

  • React.memo to prevent unnecessary re-renders
  • useMemo and useCallback for stable references
  • Component splitting so state changes don't ripple through the whole tree

Measuring the impact

After cutting JS, watch these Lighthouse metrics:

  • TBT (Total Blocking Time) should drop — usually proportional to KB removed
  • INP should improve — see INP explained
  • LCP may improve if you removed render-blocking scripts
  • Overall Performance score typically jumps 5–20 points per major change

The 80/20

If you have one hour to make your site faster, do these:

  1. Defer or async every <script> tag that isn't critical to first render
  2. Remove one third-party script you don't actively use (analytics duplicates, chat widgets, A/B tools)
  3. Replace Moment.js with date-fns (or similar one-library swap)
  4. Code-split your largest JS bundle by route

That's typically a 15–30 point performance score gain.

When JavaScript is fine

Not every site needs to be JS-light. Web apps (Figma, Linear, Google Docs) live or die by their JavaScript. Their users tolerate longer initial loads in exchange for the functionality.

But marketing pages, blogs, e-commerce product pages, and content sites should ship minimal JS. Use the right tool for the job.

The bottom line

JavaScript is unique among web resources because it costs CPU time on top of bandwidth. Every 100KB of unused JS is parse, compile, and execution time that adds nothing to your user experience.

Audit what you ship. Cut what you don't need. Defer what's left. Run a free audit and watch your score climb.

For more on improving overall site speed, see how to improve your PageSpeed Insights score and why is my website so slow.

Frequently Asked Questions

Is JavaScript bad for SEO?+

Not inherently. Google can render JavaScript. But heavy JavaScript hurts Core Web Vitals (TBT, INP, LCP), which are ranking signals. Less JavaScript usually means better SEO.

Should I remove all third-party scripts?+

No, but audit them. Most sites can remove 30–50% of their third-party scripts without losing meaningful functionality. The remaining ones should be loaded async and ideally fire after user interaction.

Does using React or Next.js make my site slow?+

Not necessarily. Server-side rendering (SSR) and static generation (SSG) in Next.js can produce sites that are as fast as static HTML. The performance problem starts when you ship a lot of client-side JavaScript and re-renders.

Rate your website for free

See how your site really performs

Run a full website health check on mobile and desktop in 30 seconds — no signup needed.

Continue reading