VOOZH about

URL: https://blog.logrocket.com/dynamic-imports-code-splitting-next-js/

⇱ Dynamic imports and code splitting with Next.js - LogRocket Blog


2022-08-25
1671
#nextjs
Chizaram Ken
129129
πŸ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

πŸš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Introduction

Optimizing performance in production environments can sometimes be an uphill task. Fine-tuning site performance cannot be overlooked, as the demerits cause slow web pages with bad UX. These sites tend to load slowly, have slow-rendering images, and in the long run, lead to increased bounce rates from site visitors as most users won’t be willing to wait for content to pop up.

πŸ‘ Dynamic imports and code-splitting with Next.js

In this tutorial, we will cover different patterns to speed-up site performance in a Next.js application.

Goals and prerequisites

At the end of this article, readers will have a clear understanding of how they can maximize performance in a Next.js web application. We’ll cover the following:

To follow along with this article, prior knowledge of the Next.js framework is required.

What are dynamic imports and code splitting?

Dynamic imports, also known as code splitting, refers to the practice of dividing bundles of JavaScript code into smaller chunks, which are then pieced together and loaded into the runtime of an application as a means to drastically boost site performance.

It was developed as an upgrade to static imports in JavaScript, which is the standard way of adding imports for modules or components at the top level of a JavaScript module using the imports syntax.

While this is a commonly used method, there are some drawbacks where performance optimization is concerned, especially in cases such as:

  • Large codebases, which create larger bundles size and result in longer load times because the build process compiles all required files into a single bundle
  • Web pages that require certain user actions, such as clicking on a navigation menu item to trigger a page load. Here, the required page is only rendered when the navigation criteria is met and could trigger a slow initial page load when components are imported statically

How do dynamic imports differ from static imports?

Unlike static imports, dynamic imports work by applying a method known as code splitting. Code splitting is the division of code into various bundles, which are arranged in parallel using a tree format, where modules are loaded dynamically β€” the modules are only imported and included in the JavaScript bundle when they are required. The more the code is split, the smaller the bundle size, and the faster the page loads.

This method creates multiple bundles that are dynamically loaded at the runtime of the webpage. Dynamic imports make use of import statements written as inline function calls.

Let’s look at a comparison. Suppose we wish to import a navigation component in our application; an example of static and dynamic imports for a navigation component is illustrated below:

Static import:

import Nav from './components/Nav'
export default function Home() {
 return (
 <div>
 <Nav/>
 </div>
 )
}

Dynamic import:

import dynamic from "next/dynamic";
import { Suspense } from "react";
export default function Home() {
 const Navigation = dynamic(() => import("./components/Nav.js"), {
 suspense: true,
 });
 return (
 <div>
 <Suspense fallback={<div>Loading...</div>}>
 <Navigation />
 </Suspense>
 </div>
 );
}

Here, the navigation component has its relative part specified in the import() block. Note that next/dynamic does not allow template literals or variables to be used in the import() argument.

Also, react/suspense has a specified fallback element, which is displayed until the imported component is available.

Benefits of dynamic imports in Next.js

Optimizing site performance as a result of implementing dynamic imports will, in turn, result in the following site benefits:

  • Faster page loads: The speed at which a website loads and displays content is crucial, as your audience wants to get things done quickly and won’t stick around for slow web pages
    • Dynamic imports also have a positive impact on image load times
  • Low bounce rates: The bounce rate, which refers to the rate at which users exit your webpage without interacting with the site, usually indicates (and is caused by) slow load times. A lower bounce rate usually means faster site performance
  • Improved site interaction time: This deals with TTI, or Time to Interactive, the time intervals between when a user requests an action, and when the user gets a result. These interactions can include clicking links, scrolling through pages, entering inputs in a search field, adding items to a shopping cart, etc.
  • Better site conversion rates: As more users gain satisfaction from using a well-optimized website, they’ll be more likely to convert

With all of these benefits, you are probably thinking about how to use dynamic imports in your application. Then, the big question is, how can we implement dynamic imports and code splitting in a Next.js application? The next section shows detailed steps on how you can achieve this.


Over 200k developers use LogRocket to create better digital experiences

πŸ‘ Image
Learn more β†’

Implementing dynamic imports and code splitting in Next.js

Next.js makes it easy to create dynamic imports in a Next application through the next/dynamic module, as demonstrated above. The next/dynamic module implements lazy loading imports of React components, and is built on React Lazy.

It also makes use of the React Suspense library to allow the application to put off loading components until they are needed, thereby improving initial loading performance due to lighter JavaScript builds.

Dynamically importing named exports

Earlier in this article, we demonstrated importing a component using next/dynamic. But we can also make dynamic imports for functions or methods exported from another file. This is demonstrated as follows:

import React from 'react'

export function SayWelcome() {
 return (
 <div>Welcome to my application</div>
 )
}
const SayHello = () => {
 return (
 <div>SayHello</div>
 )
}
export default SayHello

In the code above, we have a component, SayHello, and a named import, SayWelcome. We can make a dynamic explicit import for just the SayWelcome method, as shown below:

import dynamic from "next/dynamic";
import { Suspense } from "react";
export default function Home() {
 const SayWelcome = dynamic(
 () => import("./components/SayHello").then((res) => res.SayWelcome)
 );
 return (
 <div>
 <Suspense fallback={<div>Loading...</div>}>
 <SayWelcome />
 </Suspense>
 </div>
 );
}

The above code imports the SayHello component and then returns the SayWelcome export from the response.

Dynamically importing multiple components

Suppose we have UserDetails and UserImage components. We can import and display both components as follows:

import dynamic from 'next/dynamic'

const details = dynamic(() => import('./components/UserDetails'))
const image = dynamic(() => import('./components/UserImage'))

function UserAccount() {
 return (
 <div>
 <h1>Profile Page</h1>
 <details />
 <image />
 </div>
 )
}

const App = () => {
 return (
 <>
 <UserAccount />
 )
 </>
}

export default App

In the code above, we added dynamic imports for the UserDetails and UserImage components, then we put these components together into a single component, UserAccount. Finally, we returned the UserAccount component in the application.

Dynamic imports for client-side rendering

With the next/dynamic module, we can also disable server-side rendering for imported components and render these components on the client-side instead. This is particularly suitable for components that do not require much user interaction or have external dependencies, such as APIs. This can be done by setting the ssr property to false when importing the component:

import dynamic from 'next/dynamic'

const HeroItem = dynamic(() => import('../components/HeroItem'), {
 ssr: false,
})

const App = () => {
 return (
 <>
 <HeroItem />
 )
 </>
}

Here, the HeroItem component has server-side rendering set to false, hence it is rendered on the client-side instead.

Dynamic imports for libraries

Apart from importing local components, we can also add a dynamic import for external dependencies.

For example, suppose we wish to use Axios fetch to get data from an API whenever a user requests it. We can define a dynamic import for Axios and implement it, as shown below:

import styles from "../styles/Home.module.css";
import { React, useState } from "react";

export default function Home() {
 const [search, setSearch] = useState("");
 let [response, setResponse] = useState([]);
 const api_url = `https://api.github.com/search/users?q=${search}&per_page=5`;

 return (
 <div className={styles.main}>
 <input
 type="text"
 placeholder="Search Github Users"
 value={search}
 onChange={(e) => setSearch(e.target.value)}
 />

 <button
 onClick={async () => {
 // dynamically load the axios dependency
 const axios = (await import("axios")).default;
 const res = await axios.get(api_url).then((res) => {
 setResponse(res);
 });

 }}
 >
 Search for GitHub users
 </button>

 <div>
 <h1>{search} Results</h1>
 <ul>
 {response?.data ? (
 response && response?.data.items.map((item, index) => (
 <span key={index}>
 <p>{item.login}</p>
 </span>
 ))
 ) : (
 <p>No Results</p>
 )}
 </ul>
 </div>
 </div>
 );
}

In the code above, we have an input field to search for user names on GitHub. We use the useState() Hook to manage and update the state of the input field, and we have set the Axios dependency to be dynamically imported when the button Search for GitHub users is clicked.

When the response is returned, we map through it and display the usernames of five users whose names correspond with the search query entered in the input field.
The GIF below demonstrates the above code block in action:

πŸ‘ Dynamically importing libraries to a Next.js app

Conclusion

We learned about dynamic imports/code splitting, its advantages, and how to use it in a Next.js application in this article.

Overall, if you want to shorten the time it takes for your website to load, dynamic imports and code splitting are a must-have approach. Dynamic imports will significantly enhance the performance and user experience of your website if it has images, or if the results to be shown are dependent on user interactions.

LogRocket: Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket captures console logs, errors, network requests, and pixel-perfect DOM recordings from user sessions and lets you replay them as users saw it, eliminating guesswork around why bugs happen β€” compatible with all frameworks.

LogRocket's Galileo AI watches sessions for you, instantly identifying and explaining user struggles with automated monitoring of your entire product experience.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

πŸ‘ Image
πŸ‘ LogRocket Dashboard Free Trial Banner

Modernize how you debug your Next.js apps β€” start monitoring for free.

πŸ‘ Image
πŸ‘ Image
πŸ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

πŸ‘ Image
Emmanuel John
Jun 17, 2026 β‹… 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

πŸ‘ Image
Chizaram Ken
Jun 16, 2026 β‹… 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension β€” no new framework required.

πŸ‘ Image
Ikeh Akinyemi
Jun 12, 2026 β‹… 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo β€” with email/password login, Google OAuth, session persistence, and protected routes.

πŸ‘ Image
Chinwike Maduabuchi
Jun 9, 2026 β‹… 13 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now