Back to blogs

How to Reduce Bundle Size in Next js

September 27, 2025
5 min read
How to Reduce Bundle Size in Next js

When I first started working with Next.js, I loved how fast it was out of the box. But as the project grew, I noticed something — the bundle size kept increasing. Bigger bundles meant slower load times, worse performance on mobile, and sometimes even lower SEO scores. That’s when I realized: reducing bundle size isn’t just a technical tweak, it’s necessary for delivering a smooth user experience.


In this blog, I’ll share practical steps I use to cut down bundle size in Next.js projects. These are simple, effective techniques that can make your app feel lighter and faster.


Why Bundle Size Matters?

A heavy bundle makes your app slow before users even start interacting with it. Here’s why:

  1. Slower first load: The browser takes longer to download and parse JavaScript.
  2. Worse Core Web Vitals: Google cares about performance for SEO ranking.
  3. Bad mobile experience: On slow connections, big bundles are painful.


That’s why trimming bundle size directly impacts user satisfaction and search rankings.


Step 1: Analyze Your Bundle

You can’t optimize blindly. The first step is to see what’s inside your bundle.

  1. Use @next/bundle-analyzer:
  2. Install it with npm install @next/bundle-analyzer. Update next.config.js like this:


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


  1. Now run ANALYZE=true npm run build and you’ll see a treemap of your bundle.
  2. Try source-map-explorer:
  3. Another tool that helps you understand which files are contributing to bundle size.


The point is: know your biggest offenders before trying to fix things.


Step 2: Import Smarter

One common mistake is importing whole libraries when you only need a function or two.


  1. Bad way:
import _ from 'lodash'
const result = _.isEmpty(obj)


  1. Better way:
import isEmpty from 'lodash/isEmpty'
const result = isEmpty(obj)


The second approach includes only what’s needed.

Next.js also supports tree-shaking and the optimizePackageImports option in next.config.js to automatically trim unused parts of libraries.


Step 3: Use Dynamic Imports

Not all code needs to load on the first page render. If something is only used after interaction, load it later.

  1. Dynamic component import:
import dynamic from 'next/dynamic'
const Chart = dynamic(() => import('../components/Chart'), {
ssr: false,
loading: () => <p>Loading...</p>,
})

This keeps the chart code out of your initial bundle. It’s only loaded when the component is actually used.


Dynamic imports are perfect for:

  1. Modals
  2. Charts / graphs
  3. Third-party widgets
  4. Rarely visited sections


Step 4: Keep Heavy Code on the Server

Next.js is powerful because of server and client separation. Use that wisely.

  1. Do data fetching in getServerSideProps or getStaticProps instead of fetching everything on the client.
  2. Use Server Components (in the App Router) for logic that doesn’t need to run in the browser.
  3. Don’t ship unnecessary business logic to the client.


This not only reduces bundle size but also improves security and performance.


Step 5: Externalize or Replace Heavy Dependencies

Some libraries are simply too big. You have two choices: lazy-load them or replace them.

  1. Charts: Instead of a massive charting library, use a lighter one (or load only on demand).
  2. Date libraries: Moment.js is heavy; consider Day.js or date-fns.
  3. React → Preact: Some projects replace React with Preact for smaller bundles (though compatibility must be checked).

In next.config.js, you can also externalize certain server-only packages so they don’t end up in the client bundle.


Step 6: Optimize Assets (Not Just JavaScript)

While this blog focuses on JS bundle size, optimizing assets helps overall performance too.

  1. Images: Always use Next.js <Image> component. It handles lazy loading, compression, and responsive sizing automatically.
  2. Fonts: Import only the characters and weights you need. Google Fonts can also be self-hosted for better performance.
  3. CSS: Use Tailwind’s purge feature or other CSS tree-shaking to remove unused styles.


Step 7: Continuous Monitoring

Optimizing once isn’t enough. Every new dependency or feature can add weight.

  1. Set budgets: Use tools like size-limit to warn you if a bundle grows beyond a set size.
  2. Re-run analyzer: Make it part of your workflow before deploying.
  3. Track performance: Keep an eye on Lighthouse scores, LCP (Largest Contentful Paint), and TTI (Time To Interactive).


Quick Checklist

Here’s a simple checklist I personally follow:

  1. Analyze with @next/bundle-analyzer.
  2. Replace big dependencies with lighter ones.
  3. Import only what’s needed.
  4. Use next/dynamic for non-critical UI.
  5. Keep heavy logic server-side.
  6. Optimize images, fonts, and CSS.
  7. Monitor bundle size continuously.


Final Thoughts

Reducing bundle size in Next.js isn’t about obsessing over every single byte. It’s about focusing on what really matters: faster load times, better SEO, and happier users.

Start with the big wins like lazy-loading components and trimming dependencies. Then fine-tune with import optimizations and asset handling. Once you put these into practice, you’ll notice a clear difference in how smooth and snappy your app feels.

reduce bundle size nextjsnextjs bundle optimizationnextjs performance tipshow to reduce bundle size in nextjsoptimize nextjs build sizenextjs tree shakingnextjs dynamic importsbundle analyzer nextjsreduce javascript size nextjsnextjs code splittingnextjs performance best practicesnextjs optimize importsnextjs reduce load timeoptimize assets nextjsnextjs server components for performancenextjs seo optimization

Recent Blogs

View All