Skip to content

Inertia - Missing information for React SSR #214

@advename

Description

@advename

Issue 1: Missing Hydration Step for React SSR

Relevant Docs: AdonisJS SSR Guide

The documentation currently demonstrates how to enable SSR for Inertia by creating the inertia/app/ssr.ts file. However, when using React, it omits an important step: updating inertia/app/app.ts to use hydrateRoot instead of createRoot.

This behavior is clearly documented in the official Inertia.js docs:
https://inertiajs.com/server-side-rendering#client-side-hydration

It is also correctly implemented in the AdonisJS + React + Inertia + SSR boilerplate.

Suggestion: Please add a snippet showing how hydrateRoot should be used in app.ts when SSR is enabled.


Issue 2: SSR Allowlist and Conditional Hydration

Relevant Docs: SSR Allowlist in AdonisJS

The current guide explains the SSR Allowlist feature, which allows rendering some pages with SSR and others with CSR. However, when mixing SSR and CSR pages, developers must conditionally hydrate the app using hydrateRoot only when SSR was used — otherwise, hydration mismatch errors occur.

This subtle but critical detail is currently missing from the documentation and has led to confusion in the community, as seen in:

  • Inertia Discussion #1429 — using import.meta.env.SSR inside the if statement doesn't seem to actually work since it always returns false in the browser, meaning this is a faulty implementation
  • Intent.UI— same approach as above, ineffective.
  • Stack Overflow Answer — same approach as above, ineffective.
  • Inertia Discussion #2138 — proposes suffixing SSR pages with .ssr.tsx and using that to determine hydration method.

Recommended Solution

A more simple way is to check if the element has already been rendered server-side:

// inertia/app/app.tsx

setup({ el, App, props }) {
  const isSSR = el.childElementCount > 0

  if (isSSR) {
    hydrateRoot(
      el,
        <App {...props} />
    )
  } else {
    createRoot(el).render(
        <App {...props} />
    )
  }
}

Since only SSR-rendered pages will have child nodes, el.childElementCount > 0 provides a straightforward way to detect SSR and avoid hydration mismatches.

Alternatively, we have to add a more robust SSR flag from Inertia/AdonisJS.

Final Thoughts

I spent an entire day debugging hydration mismatch issues due to this missing detail. For developers coming from frameworks like Next.js, where SSR/CSR handling is built-in, this can be a frustrating experience.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions