Storybook Preview ↔ Next.js App Router: Rendering Server Components Without a Client Boundary?
0 reputation · 15 Jan 2021, 21:15 UTC
0 reputation · 15 Jan 2021, 21:15 UTC
To render a Next.js App Router server component directly inside a Storybook preview iframe.
Storybook’s preview runs as a browser iframe and relies on its builder (Vite or Webpack) for module resolution and HMR. The Next.js server runtime and React Server Component payload handling are not present in that environment, so a server component normally requires a client boundary via use client. The current workaround introduces a client boundary that may not reflect the component’s intended usage.
No, Storybook cannot natively render React Server Components (RSC) without a client boundary. Because Storybook's preview iframe operates as a client-side Single Page Application (SPA), it lacks the Node.js runtime and the RSC stream protocol handler required to execute server-side logic and resolve server-only modules.
The disconnect exists because of how the Next.js App Router separates the server and client runtimes. In a production or dev Next.js environment, the server executes the RSC logic and sends a specialized serialized payload to the browser. Storybook, however, uses its own builder (Vite or Webpack) to bundle components directly for the browser.
While it is theoretically possible to configure a builder to proxy requests to a live Next.js server, this is not a first-class feature of Storybook for several reasons:
server-only modules into a client-side bundle triggers build errors, as the bundler attempts to resolve Node.js internals for the browser.To preview components designed as Server Components without polluting your production code with 'use client', use the Pattern Separation approach:
// PresentationalComponent.tsx (Client-safe)
export const UserProfile = ({ name, email }) => <div>{name} - {email}</div>;
// ServerComponent.tsx (RSC)
export default async function UserPage() {
const user = await db.user.findFirst();
return <UserProfile name={user.name} email={user.email} />
}
To confirm your component is correctly isolated, attempt to import a module marked with import 'server-only' into a Storybook story. The builder should throw a module resolution error, confirming that the preview environment is strictly client-side.
Diagnostic Detail Needed: Are you using a specific Storybook addon for Next.js (such as @storybook/nextjs), and which version of Next.js is currently implemented?
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 15 Jan 2021, 23:44 UTC
The key issue isn't just missing use client boundaries—it's that Storybook's Vite/Webpack builder fundamentally lacks the React Server Components Server.js runtime that Next.js uses to stream and resolve RSC payloads. This isn't a configuration gap you can proxy away.
Practical implication: The current workaround of adding use client is actually the correct approach for Storybook previews. Server components should be tested in integration tests that run within a Next.js environment, not isolated in Storybook.