Skip to content
Now accepting new projects — limited slots available. Get started →
Performance · Updated Aug 4, 2026

What is JavaScript Bundle Size?

JavaScript bundle size is the total weight of JS files shipped to a browser that directly affects page load and interactivity.

What is JavaScript Bundle Size?

JavaScript bundle size is the total byte weight of all JavaScript files delivered to a user's browser for a given page or route. It's typically measured in kilobytes (KB) after gzip or Brotli compression.

Bundle size directly affects Time to Interactive (TTI), Interaction to Next Paint (INP), and Largest Contentful Paint (LCP) — three of Google's Core Web Vitals. Every kilobyte of JavaScript costs roughly 1ms of parse/compile time on a mid-range mobile device. So a 300 KB bundle can add 300ms+ of blocking time before a page becomes interactive.

The HTTP Archive's 2025 data shows the median mobile page ships ~500 KB of compressed JavaScript, up from ~450 KB in 2022.

Reducing bundle size is one of the highest-ROI performance wins. We've shipped this on 50+ projects and consistently see INP improvements of 30-50% when we cut JS payloads by half. A common first step is analyzing your bundle with tools like webpack-bundle-analyzer or @next/bundle-analyzer.

How it works

When you build a modern web app with a bundler like webpack, Vite, Turbopack, or esbuild, your source code and its node_modules dependencies get concatenated into one or more output files — bundles. The total size of these files is your bundle size.

There are two measurements that matter:

  • Uncompressed size — what the browser actually parses and executes
  • Transfer size — what crosses the network after gzip/Brotli compression (typically 60-80% smaller)

Both matter, but for different reasons. Transfer size affects download time. Uncompressed size affects parse and execution time on the main thread.

Here's how to check your Next.js bundle size:

# Install the analyzer
npm install @next/bundle-analyzer

# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({ /* your config */ });

# Run the analysis
ANALYZE=true npm run build

This generates a treemap visualization showing exactly which dependencies are eating your budget. Common offenders include moment.js (330 KB uncompressed — switch to date-fns or dayjs), full lodash imports (use lodash-es with tree-shaking), and icon libraries that ship thousands of SVGs.

Our preferred stack at Social Animal uses Next.js with Turbopack, which handles tree-shaking and code-splitting by default. But defaults aren't enough. You still have to audit what's actually ending up in the client bundle.

When to use it

Bundle size isn't something you "use" — it's something you monitor and manage. Here's when to prioritize it:

Actively optimize when:

  • Your Lighthouse Performance score is below 80 on mobile
  • INP exceeds the 200ms "good" threshold
  • Your JS transfer size exceeds 150 KB per route
  • You're shipping a SaaS product or e-commerce site where conversion depends on speed
  • You've just added a new dependency and want to know its cost

Deprioritize when:

  • You're building an internal tool where network conditions are controlled
  • Your page is mostly static HTML with minimal JS (e.g., an Astro content site with zero client JS)
  • You're pre-launch and still iterating rapidly on features — optimize once the API surface stabilizes

A useful rule of thumb: set a performance budget of 170 KB compressed JS per route. If you exceed it, investigate before shipping.

JavaScript Bundle Size vs alternatives

Bundle size is one of several performance metrics. Here's how it relates to adjacent concepts:

Concept What it measures Relationship to bundle size
Tree-shaking Removal of unused exports at build time Directly reduces bundle size
Code-splitting Breaking one bundle into multiple route-based chunks Reduces per-route bundle size
Lazy loading Deferring JS loading until needed Reduces initial bundle size
INP Responsiveness to user interaction Affected by total JS on the page
Transfer size Bytes over the network Compressed version of bundle size
Total Blocking Time (TBT) Main thread blocking during load Caused by large bundles

Bundle size is the root cause. Metrics like INP and TBT are the symptoms. Fix the cause and the symptoms improve.

Real-world example

On a recent Next.js 15 e-commerce project, our initial route bundle was 410 KB compressed. Lighthouse mobile score: 62. INP was 380ms on a Moto G Power.

We ran @next/bundle-analyzer and found three problems: a full chart.js import on the product page (it was only used on the dashboard), react-icons importing the entire icon set, and a date formatting library pulling in locale data for 40+ languages.

Fixes: dynamic import for chart.js behind the dashboard route, switched to @phosphor-icons/react with named imports, replaced the date library with Intl.DateTimeFormat. Total time: about 4 hours.

Result: bundle dropped to 145 KB compressed. Lighthouse hit 91. INP fell to 120ms. Conversion rate on mobile increased 14% over the following two weeks.

Frequently asked questions about JavaScript Bundle Size

Is JavaScript bundle size the same as page weight?
No. Page weight includes everything — HTML, CSS, images, fonts, video, and JavaScript. Bundle size refers specifically to the JavaScript portion. On many modern SPAs, JavaScript can account for 50-70% of total page weight, which is why it gets so much attention. But a page with a 5 MB hero image and 100 KB of JS has a large page weight and a small bundle size. Both metrics matter for different reasons: images affect LCP, while JavaScript affects INP and TBT.
When did JavaScript bundle size become a standard performance concern?
Bundle size became a serious topic around 2015-2016 when single-page apps built with React, Angular 2, and webpack became mainstream. Before that, most sites shipped small jQuery scripts. The turning point was Addy Osmani's 2017 article 'The Cost of JavaScript' which showed that JS byte-for-byte is more expensive than images because of parse and compile costs. Google formalized this concern with Web Vitals in 2020 and INP replacing FID as a Core Web Vital in March 2024, making JS execution cost a direct ranking factor.
What's the best alternative to reducing JavaScript bundle size?
The real alternative is shipping less JavaScript in the first place. Frameworks like Astro (our preferred choice for content sites) ship zero client JS by default — you opt components into hydration rather than opting them out. Server Components in Next.js 13+ take a similar approach by keeping components on the server unless you mark them with `'use client'`. If you can't reduce the amount of JS, code-splitting and lazy loading are your next best options. They don't reduce total JS — they just defer what loads until it's actually needed.
What is a good JavaScript bundle size for a web page?
For a good user experience on mid-range mobile devices, aim for under 170 KB of compressed JavaScript per route. Alex Russell's performance budget research suggests a total JS budget of around 300-350 KB uncompressed for pages targeting global audiences on 4G connections. Anything above 500 KB compressed per route is a red flag. For context, the median website ships roughly 500 KB compressed — and the median website isn't fast. We set budgets per project based on the target audience's device profile, but 170 KB compressed is a solid default starting point.
Get in touch

Let's build
something together.

Whether it's a migration, a new build, or an SEO challenge — the Social Animal team would love to hear from you.

Get in touch →