Hydration Error - SSR

Please fill out as many of the following questions as possible so we can help you promptly! If you don’t know how to answer or it does not apply, feel free to remove it or leave it blank.

Builder content link

What are you trying to accomplish
I wish to integrate builder.io and register my custom components and pages in SSR in nextJS App router.

Screenshots or video link


Code stack you are integrating Builder with
NextJS APP router

I wish to resolve this hydration error and avoid client-side render of the builder pages. How do I do it? I went through the documentation but could not find anything which helps me achieve the server side rendering and also avoid this hydration error.

import { builder } from "@builder.io/sdk";
import { RenderBuilderContent } from "@/components/builder";

builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY ?? "");

type PageProps = {
  params: {
    page: string[];
  };
};

export default async function Page(props: Readonly<PageProps>) {
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  const content = await builder
    .get("page", {
      userAttributes: {
        // Use the page path specified in the URL to fetch the content
        urlPath: "/" + (props?.params?.page?.join("/") || ""),
      },
      // Set prerender to false to return JSON instead of HTML
      prerender: false,
    })
    // Convert the result to a promise
    .toPromise();

  return (
    <div className="mt-20 justify-center w-full">
      {/* Render the Builder page */}
      {/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */}
      <RenderBuilderContent content={content} />
    </div>
  );
}

{
  "name": "podium-entertainment",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "dev:ssl": "next dev --experimental-https",
    "build": "next build",
    "start": "next start",
    "test": "jest --watchAll=false",
    "test:watch": "jest --watchAll",
    "test:coverage": "jest --coverage",
    "lint": "next lint",
    "check-types": "tsc --pretty --noEmit",
    "prepare": "husky install",
    "cypress:open": "cypress open"
  },
  "dependencies": {
    "@builder.io/dev-tools": "^1.0.1",
    "@builder.io/react": "^3.2.6",
    "@builder.io/sdk": "^2.2.2",
    "@prisma/client": "^5.8.0",
    "@radix-ui/react-popover": "^1.0.7",
    "clsx": "^2.1.0",
    "next": "14.0.4",
    "next-auth": "^4.24.5",
    "react": "^18",
    "react-dom": "^18",
    "tailwind-merge": "^2.2.1"
  },
  "devDependencies": {
    "@next/eslint-plugin-next": "^14.0.4",
    "@testing-library/jest-dom": "^6.2.1",
    "@testing-library/react": "^14.1.2",
    "@types/jest": "^29.5.11",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "@typescript-eslint/eslint-plugin": "^6.17.0",
    "@typescript-eslint/parser": "^6.17.0",
    "autoprefixer": "^10.0.1",
    "cypress": "^13.6.3",
    "eslint": "^8",
    "eslint-config-next": "14.0.4",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-cypress": "^2.15.1",
    "eslint-plugin-jest": "^27.6.3",
    "eslint-plugin-jest-dom": "^5.1.0",
    "eslint-plugin-prettier": "^5.1.2",
    "eslint-plugin-testing-library": "^6.2.0",
    "husky": "^8.0.0",
    "jest": "^29.7.0",
    "jest-canvas-mock": "^2.5.2",
    "jest-environment-jsdom": "^29.7.0",
    "lint-staged": "^15.2.0",
    "postcss": "^8",
    "prettier": "^3.1.1",
    "prisma": "^5.7.1",
    "tailwindcss": "^3.3.0",
    "ts-jest": "^29.1.2",
    "ts-node": "^10.9.2",
    "typescript": "^5"
  }
}

And I am still facing issue of empty state object in builder.io I wanted to bind my data but I am unable to.

Please help me resolve this. @manish-sharma

Hello @sohail,

For resolving hydration errors, we recommend you try our plugin Hydration Overlay

hi @manish-sharma
I tried this but I am unable to find the issue.

const withBuilderDevTools = require("@builder.io/dev-tools/next")();


const {
  withHydrationOverlay,
} = require("@builder.io/react-hydration-overlay/next");

/** @type {import("next").NextConfig} */
const nextConfig = withBuilderDevTools({
  reactStrictMode: true,
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "podiumaudio.com",
        port: "",
        pathname: "/wp-content/uploads/**",
      },
      {
        protocol: "https",
        hostname: "m.media-amazon.com",
        port: "",
        pathname: "/images/**",
      },
      {
        protocol: "https",
        hostname: "podiumpublishing.box.com",
        port: "",
        pathname: "/shared/static/**",
      },
      {
        protocol: "https",
        hostname: "cdn.builder.io",
      },
      {
        protocol: "https",
        hostname: "s3-alpha-sig.figma.com",
      },
      {
        protocol: "https",
        hostname: "www.figma.com",
      },
      {
        protocol: "https",
        hostname: "image.tmdb.org",
      },
    ],
  },
});


module.exports = withHydrationOverlay({
  /**
   * Optional: `appRootSelector` is the selector for the root element of your app. By default, it is `#__next` which works
   * for Next.js apps with pages directory. If you are using the app directory, you should change this to `main`.
   */
  appRootSelector: "main",
})(nextConfig);

module.exports = nextConfig;

import "./globals.css";
import { ReactNode } from "react";
import type { Metadata } from "next";
import Header from "@/components/header/header";
import SignUp from "@/components/sign-up/sign-up";
import Footer from "@/components/footer/footer";
import { gintoNord, openSans } from "./fonts";
import { HydrationOverlay } from "@builder.io/react-hydration-overlay";

export const metadata: Metadata = {
  title: "Podium Entertainment",
  description: "Home Page for Podium Entertainment",
  icons: {
    icon: [
      {
        media: "(prefers-color-scheme: light)",
        url: "/images/icon-dark.png",
        href: "/images/icon-dark.png",
      },
      {
        media: "(prefers-color-scheme: dark)",
        url: "/images/icon.png",
        href: "/images/icon-light.png",
      },
    ],
  },
};
const RootLayout = ({ children }: { children: ReactNode }) => {
  return (
    <html lang="en" className={`${openSans.variable}`}>
      <body className={gintoNord.className}>
        <Header />
        <HydrationOverlay>{children}</HydrationOverlay>
        <SignUp />
        <Footer />
      </body>
    </html>
  );
};

export default RootLayout;

import { builder } from "@builder.io/sdk";
import { RenderBuilderContent } from "@/components/builder";

builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY ?? "");

type PageProps = {
  params: {
    page: string[];
  };
};

export default async function Page(props: Readonly<PageProps>) {
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  const content = await builder
    .get("page", {
      userAttributes: {
        // Use the page path specified in the URL to fetch the content
        urlPath: "/" + (props?.params?.page?.join("/") || ""),
      },
      // Set prerender to false to return JSON instead of HTML
      prerender: false,
    })
    // Convert the result to a promise
    .toPromise();

  return (
    <div className="mt-20 justify-center w-full">
      {/* Render the Builder page */}
      {/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */}
      <RenderBuilderContent content={content} />
    </div>
  );
}

This is happening only on the builder pages.
I even tried wrapping the content inside body as whole and also only children inside Overlay but nothing seems to be working.

Hello @sohail,

Could you please confirm if you encounter the hydration error even for newly created Builder content without any custom content, or does the error only occur when using custom components?

I just created this page and added a simple text from builder’s basic UI elements (Not custom components) and this took a lot of time to appear on the live page and multiple refreshes. and when it loaded I got this issue.

Hello @sohail,

Unfortunately, it’s challenging for us to investigate the hydration issue since you’re developing locally, and we’re unable to reproduce the error using our own setup to preview your content. Would you be able to provide a minimum reproducible repository (repo) of your project where we can reproduce the issue you’re experiencing?

Sharing a repo will enable us to closely examine your setup and identify the root cause of the hydration problem more effectively.

Thanks,

I’m having the same issue here with the same elements called out in the hydration error. When I use the hydration overlay, essentially the entire page is the hydration error. I’ve compared this project to other Builder projects of mine and I just can’t determine what’s going on.

The Builder content takes a second to appear on page load, whereas other projects don’t seem to experience the same problem in local development.

Would love to know if there’s something obvious I’m missing here.

For anyone that ends up here with the same issue, I can’t explain it, but make sure that your RenderBuilderContent component passes the props “model” instead of “modelType”

Wrong:

<RenderBuilderContent content={content} modelType="page" />

Right:

<RenderBuilderContent content={content} model="page" />

I’m running into the same thing myself. Data that I fetch from Builder’s Content API and pass into my custom component via that data prop throws a hydration error.

If I use a built in Builder component like, “Text” I don’t get the hydration error. Why would this be happening? I’m using Next.js 14 App Router.