--- name: ssr-nextjs description: MUI server-side rendering with Next.js — App Router, Pages Router, RSC compatibility, Emotion cache, and Pigment CSS triggers: - SSR - Next.js - server-side rendering - App Router - server components - RSC - Emotion cache - ThemeRegistry allowed-tools: - Read - Glob - Grep - Bash - Write - Edit globs: - "*.tsx" - "*.ts" - "next.config.*" - "app/layout.*" --- # MUI SSR with Next.js ## 1. Next.js App Router Setup (v13+) The App Router requires a client-side ThemeRegistry component that flushes Emotion's server-generated styles into the document head via `useServerInsertedHTML`. ### ThemeRegistry client component ```tsx // src/components/ThemeRegistry/EmotionCache.tsx 'use client'; import * as React from 'react'; import createCache from '@emotion/cache'; import { useServerInsertedHTML } from 'next/navigation'; import { CacheProvider } from '@emotion/react'; export default function NextAppDirEmotionCacheProvider( props: { options: Parameters[0]; children: React.ReactNode } ) { const { options, children } = props; const [registry] = React.useState(() => { const cache = createCache(options); cache.compat = true; const prevInsert = cache.insert; let inserted: { name: string; isGlobal: boolean }[] = []; cache.insert = (...args) => { const [selector, serialized] = args; if (cache.inserted[serialized.name] === undefined) { inserted.push({ name: serialized.name, isGlobal: !selector, }); } return prevInsert(...args); }; return { cache, flush: () => { const prev = inserted; inserted = []; return prev; } }; }); useServerInsertedHTML(() => { const names = registry.flush(); if (names.length === 0) return null; let styles = ''; let dataEmotionAttribute = registry.cache.key; const globals: { name: string; style: string }[] = []; for (const { name, isGlobal } of names) { const style = registry.cache.inserted[name]; if (typeof style === 'string') { if (isGlobal) { globals.push({ name, style }); } else { styles += style; dataEmotionAttribute += ` ${name}`; } } } return ( <> {globals.map(({ name, style }) => (