DEV Community

Cover image for Avoiding SSR Pitfalls: Using `next/dynamic` in Your Next.js App
Shinji NAKAMATSU
Shinji NAKAMATSU Subscriber

Posted on

Avoiding SSR Pitfalls: Using `next/dynamic` in Your Next.js App

tl;dr

Components wrapped in dynamic() as shown below are not rendered on the server-side but are exclusively rendered on the client-side.

export const PurchaseButton = dynamic(
  Promise.resolve((props: Props) => {
    // Component implementation
  }),
  { ssr: false }
)
Enter fullscreen mode Exit fullscreen mode

The Problem

When components intended for server-side rendering (SSR) are implemented as demonstrated below, discrepancies can arise between Server-side and Client-side rendering, potentially leading to errors during React's hydration phase:

(error message)

Unhandled Runtime Error
Error: Text content does not match server-rendered HTML.

See more info here: https://nextjs.org/docs/messages/react-hydration-error
Enter fullscreen mode Exit fullscreen mode

Followings are possible causes:

  • Adapting rendering based on the presence or absence of the window object.
  • Content changes based on rendering timing, such as the current date and time.

For more in-depth information, please refer to the following link:

How to Address this from the Component Consumer Side

To resolve such issues, one approach is to prevent the targeted component from being rendered on the Server-side.

Solution 2: Disabling SSR on specific components

To achieve this, you can leverage next/dynamic. However, in the official documentation, it is often introduced in the context of dynamic imports, possibly with file splitting in mind.

Reference: Optimizing: Lazy Loading | Next.js

const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)
Enter fullscreen mode Exit fullscreen mode

By following this pattern, the side that utilizes the component (component consumer side) needs to be aware of next/dynamic.
If you need the flexibility to toggle between enabling and disabling SSR on a case-by-case basis, that's perfectly fine. However, if the specific component is intended to be non-SSR compliant regardless of its usage context, it's best to handle this within the component itself.

Addressing the Issue Within the Targeted Component

By wrapping the targeted component entirely with dynamic(...), there's no need for the component consumer to be mindful of SSR considerations. It's worth noting that the first argument of dynamic() should be a Promise<...>, which typically involves passing the component wrapped in Promise.resolve().

export const PurchaseButton = dynamic(
  Promise.resolve((props: Props) => {
    // Component implementation
  }),
  { ssr: false }
)
Enter fullscreen mode Exit fullscreen mode

Conclusion

Server-side rendering (SSR) offers advantages like faster page loads and SEO benefits. Nevertheless, certain components may introduce issues due to disparities between server-side and client-side behaviors.

Through the use of Next.js's next/dynamic feature, developers can selectively disable SSR for specific components, ensuring smoother hydration processes and overall enhanced application resilience.

This approach not only provides flexibility in managing components with client-specific dependencies but also streamlines the development process by reducing SSR-related bugs.

Top comments (0)