# Frontend Bundle Size Optimization

Source: https://www.techinterview.org/post/3233475204/frontend-bundle-size-optimization/
Updated: 2026-06-30 · techinterview.org

Bundle size is one of the most-tracked frontend metrics. Every kilobyte costs render time, especially on mobile. Senior frontend interviews probe whether you have done bundle analysis and applied targeted optimizations — not just "I use code splitting."

## Setting a budget

For a typical web app:

- Initial JS: <200KB compressed

- Initial CSS: <50KB compressed

- Vendor chunk: <150KB compressed

- Each route chunk: <100KB compressed

For static / content sites: <100KB total. For complex apps (Figma, Linear): higher budget acceptable.

## Bundle analysis tools

- vite-bundle-visualizer (Vite)

- rollup-plugin-visualizer

- webpack-bundle-analyzer

- source-map-explorer (post-build)

Always run on production builds. Look for: unexpected large libraries, duplicates, dependencies you forgot you imported.

## Dependency audit

The biggest wins come from cutting heavy dependencies:

- **moment.js (200+KB):** replace with date-fns (modular) or Day.js (2KB)

- **lodash (full):** import per-function (lodash/debounce) or replace with native

- **chart.js / D3 full:** bundle only the parts you use

- **icon libraries:** import individual icons, not the whole library

## Tree shaking effectiveness

Tree shaking only works if:

- The library is ESM (or has ESM build)

- The library is side-effect-free (or its package.json declares so)

- You import named exports, not entire modules

Bad: `import _ from 'lodash'` imports everything

Good: `import { debounce } from 'lodash'` still might bundle everything if lodash is not properly tree-shaken

Best: `import debounce from 'lodash/debounce'` imports only debounce

## Code splitting

Beyond route-based:

- Heavy components on demand (charts, editors, players)

- Separate vendor and app bundles

- Split rarely-used dialogs and modals

## Polyfills

Modern apps target modern browsers. Don't ship polyfills for IE if you do not support IE.

Use `browserslist` config; tools like Babel and PostCSS use it to determine what to polyfill.

## Image impact on bundles

Small images sometimes get inlined as data URIs. Disable for anything >1KB. Inline blocks tree shaking and bloats main bundle.

## CSS bundle size

- PurgeCSS (or Tailwind's built-in) removes unused classes

- CSS Modules scope rules to components — used CSS only

- Avoid global CSS frameworks (Bootstrap full) for SaaS apps

## Compression

- gzip: ~70% reduction

- Brotli: ~80% reduction; supported by all modern browsers

- Configure server / CDN to serve Brotli when supported

## Module federation pitfall

Module federation can cause duplicate dependency loading if shared modules are not configured. Audit when using.

## Server-side rendering

SSR ships HTML before JS. Initial bundle does not need to be tiny — but hydration JS still does.

React Server Components reduce client bundle dramatically. Components run on the server; do not ship to client.

## The "I do not know what is in there" problem

Many engineers do not know what their bundle contains. Steps:

- Run a bundle analyzer

- Identify the top 10 largest dependencies

- For each, decide: keep, replace, or remove

- Rebuild and verify

Often the first such pass cuts 30–50%.

## Common antipatterns

- Importing entire icon library

- Multiple date libraries in the same bundle (moment + date-fns + dayjs)

- Loading polyfills for every browser

- One massive bundle (no splitting)

- Unused legacy code (delete it)

## Frequently Asked Questions

### What is the biggest single optimization for most apps?

Removing moment.js. Many apps still ship it. Switching to Day.js or date-fns alone saves 100+KB.

### How do I track bundle size over time?

CI step that fails the build if bundle exceeds threshold. bundlewatch, size-limit, statoscope.

### What about React itself — can I make it smaller?

React + React DOM is ~140KB minified. Preact is a 3KB drop-in for ~80% of React APIs. Used by smaller apps targeting mobile.
