4 min read • Jul 29, 2026
Optimizing React load time through JavaScript bundle optimization
Bundling optimization improves React application performance by reducing JavaScript bundle size and loading code only when it's needed through code splitting, lazy loading, and production build optimizations.

Bundling
Bundling is the process of combining all the JavaScript files and imported modules into one or more files called bundles. Most React applications use bundlers such as Webpack, Rollup, or Vite to create bundles.
As an application grows, its bundle becomes larger, especially if it includes third-party libraries. Large bundle sizes take longer to download, parse, and execute, which increases page load time and data usage.
There are two primary ways to optimize large JavaScript bundles:
- Reducing the actual size of the bundle by removing unnecessary code and dependencies
- Split the bundle into smaller chunks so that only the code needed for the current page or feature is loaded initially, while the remaining code is downloaded on demand.
Code-splitting
Code splitting divides one large JavaScript bundle into multiple smaller bundles. Instead of downloading every component immediately, the browser downloads only the code needed for the current page. Additional bundles are fetched as users navigate through the application. React applications implement code splitting with React.lazy() together with Suspense, which uses dynamic imports internally.
Dynamic imports - import()
Dynamic imports allow JavaScript modules to be loaded only when they are needed rather than the initial page load. Instead of importing a module at the top of a file, you can call import() when it’s required. Calling import() creates a separate JavaScript chunk that is downloaded on demand.
For example, instead of loading the utility immediately:
import { calculateTotal } from "./utils";
function App() {
console.log(calculateTotal());
}we can load it when the user clicks a button:
function App() {
async function handleClick() {
const { calculateTotal } = await import("./utils");
console.log(calculateTotal());
}
return <button onClick={handleClick}>Calculate</button>;
}React.lazy()
React.lazy() lets you treat dynamic imports as regular components. React.lazy() takes a function that calls a dynamic import(). It returns a Promise which resolves to a module with a default export containing a React component.
Lazy loading is commonly used with route-based components. For example, the page will be loaded when the user navigates to About:
// instead of
import About from "./About";
// The About component is downloaded only when React renders it
import { lazy } from "react";
const About = lazy(() => import("./About"));Suspense
A lazy-loaded component isn't available immediately because it must first be downloaded. Lazy-loaded or asynchronous components must be wrapped in suspense. Suspense allows us to display a fallback until the promise returned by dynamic import resolves.
The fallback can be any React component, for example, a loading message, spinner, or skeleton screen. Once the component finishes loading, React automatically replaces the fallback with the actual component.
For example:
import { lazy, Suspense } from "react";
const About = lazy(() => import("./About"));
function App() {
return (
<Suspense fallback={<h2>Loading...</h2>}>
<About />
</Suspense>
);
}Make the bundle smaller
Analyze the bundle
Bundle analysis tools show exactly what's included in the JavaScript bundle. They display each dependency and how much space it occupies. This helps identify large packages or duplicate code that could be optimized. Measuring your bundle is the first step toward improving it.
Removing unused dependencies
Every package you install increases the potential size of your application. Although bundlers won’t include unused dependencies in the final bundle, removing packages you no longer use will reduce package installation time and remove unused code dependencies. You can find unused dependencies with tools like knip.
Replace heavy dependencies
After identifying large libraries, replace them with lighter alternatives or built-in browser features if possible.
Tree shaking
Tree shaking removes unused JavaScript during the production build. If you import only part of a module, unused exports are omitted from the final bundle. This reduces the amount of code users download. Modern bundlers such as Vite and Webpack automatically perform tree-shaking with ES modules.
To help identify what to remove during tree-shaking, consider importing only what you use instead of importing the entire library:
import _ from"lodash";
_.debounce(search,300);Import only the functions you need:
import debounce from "lodash/debounce";
debounce(search,300);Production build
Most hosting platforms, such as Vercel and Netlify, automatically create a production build during deployment. If you're deploying manually, be sure to run npm run build first and deploy the generated production files rather than your source code.
Development builds include debugging information, warnings, and source maps that increase file size. A production build removes these extras and applies optimizations such as minification and tree shaking. This creates smaller files that load faster.