This content originally appeared on DEV Community and was authored by Sachin Maurya
Intro:
Ever noticed your website feels heavy even when it’s mostly static content?
That’s because you’re shipping everything at once, even if the user only needs 10%.
In this part of the series, we’ll explore Code Splitting, Dynamic Imports, and Bundle Analysis in React & Next.js — essential techniques that helped me shave off 40–80% of loading time across real projects.
You’ll learn:
- What code splitting is and why it matters
- How to use
next/dynamic
for dynamic imports - How to analyze and reduce your JavaScript bundles
- Real examples from a live project I worked on at my company
What Is Code Splitting?
Code Splitting is a technique where your app is divided into small chunks instead of one big JavaScript file.
Benefits:
- Faster initial load time
- Load only what’s needed
- Reduces Time to Interactive (TTI)
Dynamic Imports with next/dynamic
Real-World Use Case:
In one of our projects (Kreate Energy, built with Next.js + GraphQL), we had a heavy modal component that included chart libraries.
We didn’t want to load it until needed.
The Fix:
import dynamic from 'next/dynamic';
const HeavyModal = dynamic(() => import('../components/HeavyModal'), {
ssr: false,
loading: () => <p>Loading...</p>,
});
This delayed the load until the modal was actually triggered.
Result?
- ~45% reduction in initial JS size
- ~2.5s faster TTI on mobile
How Dynamic Imports Work
When using dynamic()
, Next.js creates a separate bundle for that module.
This chunk is only loaded when the component is rendered.
Bonus: Add ssr: false
if it uses browser-only features like window
or navigator
.
Bundle Analysis
Use this to see what’s bloating your app.
Setup:
Install:
npm install @next/bundle-analyzer
Add this to next.config.js
:
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
// your config
});
Run:
ANALYZE=true npm run build
Insights:
- You’ll get an interactive visualization of all packages
- Identify huge libraries you can replace or lazy load
- Example: Replacing
moment.js
withdate-fns
saved us 180 KB
Bonus Tips for Bundle Slimming
- Avoid unnecessary dependencies (lodash → lodash-es or selective imports)
- Move feature-rich pages to
dynamic()
- Compress images and lazy-load them
- Remove unused code or dead routes
Real-World Win: Kreate Technologies Website
I applied this on our corporate site:
- Broke major sections into lazy-loaded dynamic components
- Used
next/image
+ responsive sizing - Preloaded only critical routes
Result:
- 85 → 97 Lighthouse performance score
- Faster page-to-page transitions
- Easier debugging of production builds
Takeaways
- Use
next/dynamic
to split components like charts, modals, maps - Analyze your build output regularly — don’t ship what you don’t need
- Don’t optimize too early — measure first, act later
What’s Next?
In Part 6, I’ll cover State Management Battle: Redux Toolkit vs Zustand vs React Query — real comparisons from my day job, with wins, fails, and how to choose wisely.
Let’s Connect
If you found this helpful, drop a below or DM me on LinkedIn.
I post real-world frontend struggles and solutions weekly.
Related Posts in This Series:
- Part 1: Performance Tips I Wish I Knew Earlier
- Part 2: useState vs useReducer
- Part 3: Lighthouse, Web Vitals & PageSpeed
- Part 4: Debounce, Throttle & Request Batching
This content originally appeared on DEV Community and was authored by Sachin Maurya