You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Storybook is moving docgen from the preview bundle to the dev server. This improves the component metadata produced by Storybook’s MCP and also in Storybook’s auto-generated documentation.
Component metadata (props, descriptions, argTypes) and story snippets are extracted server-side and exposed through a new architecture we call the Open Service Architecture. For now, this change is React-only, but we’re planning on expanding it to the other core frameworks soon.
This RFC is open for feedback on the docgen output and the story snippet format. It is also the place to ask questions and report issues after enabling the flag in your project.
If you try this in your project, please leave a comment with what worked, what broke, and anything that surprised you. If you know that you are experiencing an actual bug, please open an issue with a reproduction and reference it here.
Background
Today, Storybook produces similar component documentation through several separate paths:
Controls and ArgTypes rely on docgen injected into the preview bundle at build time (react-docgen or react-docgen-typescript via Vite/Webpack plugins).
Autodocs code blocks render JSX dynamically at runtime via a special decorator.
Manifests and MCP run their own docgen pass over the full story index, often duplicating work the preview already did.
These are all different ways to compute the same data, using different analysis algorithms, leading to inaccurate and inconsistent results. Preview startup is blocked on docgen plugins, and story rendering is slower than necessary because it must compute docgen before rendering the story. MCP manifest generation can be slow because it re-extracts everything. We already built React Component Meta (RCM) for MCP, but it was not wired into the main docs UI.
The docgen server unifies these consumers into a single server-side pipeline.
Controls, ArgTypes, Description, and Source blocks read from the core/docgen open service, which computes them on the server.
Autodocs snippets and the Code panel read from the core/story-docs open service.
Manifests and MCP use a ref-based format with per-component JSON snapshots.
You do not need experimentalCodeExamples. The story-docs service replaces it.
Data pipeline
Overview
CSF story file
│
├─► core/docgen (props, descriptions, argTypes, subcomponents)
│ via React Component Meta + TypeScript Language Service
│
└─► core/story-docs (per-story snippets, import block, story descriptions)
via CSF static analysis only (no RCM)
Both services register at server startup when experimentalDocgenServer is enabled. Renderer packages contribute through preset hooks:
experimental_docgenProvider
experimental_storyDocsProvider
Only @storybook/react ships providers today, but anyone can hook into these preset properties and provide their own docgen/story-docs server side - it supports composing multiple providers together to form a single docgen result for a given component/story. If you’re feeling adventurous, you can take a look at how @storybook/react hooks into these presets and add your own metadata. Although the API and format are still experimental and subject to change, especially as we expect to learn more from expanding the support to the other frameworks in the coming months.
Extraction and caching
Storybook indexes CSF files as usual.
When a consumer asks for a component (Controls panel, autodocs block, MCP tool, etc.), the server resolves the story index entry and runs the provider chain.
Results are stored in the service state or written to static JSON snapshots on storybook build. The service state is shared and automatically synced across all the runtimes (server, manager, preview).
In dev, the module graph service watches for file changes and triggers re-extraction of affected components.
Each file wraps payloads in a { "components": { "<id>": { ... } } } envelope so JSON Pointer refs stay stable. This is an internal construct and not a public API, and it’s not unlikely that we will change this in patch versions, but feel free to take a look anyway.
Manifest index format
manifests/components.json becomes a lightweight index. Each component row carries summary fields inline and $ref pointers to the full payloads:
Agents and MCP tools can load components one at a time rather than parse a single large inline manifest.
core/docgen payload
One payload per component id:
Field
Description
id, name, path
Component identity and CSF file path
description, summary
From component JSDoc and CSF meta
jsDocTags
Parsed JSDoc tags on the component
argTypes
Renderer-converted prop table for Controls
subcomponents
Same shape for declared subcomponents
reactComponentMeta
Raw RCM output (React-specific, kept for tooling)
error
Extraction failure details
Story snippets and file-level imports are not in this payload. They live in core/story-docs.
Custom argTypes from CSF meta and story parameters are merged at read time in the UI, same as before.
core/story-docs payload
One payload per component id:
Field
Description
id, name, path
Component identity and CSF file path
import
Suggested import statement(s) for the stories file
stories
Map of story id → { id, name, snippet, description, summary, error? }
error
File-level extraction failure
Story snippet format
We would love feedback on this section in particular.
How snippets are generated
For each story export in a CSF file, Storybook parses the file with Babel/recast and builds a React JSX snippet that shows how the component is used. The output looks like a small React component rather than the CSF story definition.
Roughly:
Read the story file and work out what the story is doing: the export, the effective args (meta defaults + story overrides), and the render function if there is one.
Build a JSX example from those args. Simple stories become something like () => <Button disabled>Click me</Button>. Stories with a custom render keep that JSX shape, but with args filled in so you see concrete prop values instead of {...args} or args.label.
Format it for display as a small React component, with imports prepended when the snippet appears in autodocs or the Code panel.
The goal is more complete usage examples; this is not just the JSX, but an actual React component, complete with imports.
When the render function cannot be resolved (for example, an imported template), Storybook falls back to synthesizing JSX from the component name and merged args.
Snippets still support per-story customization via parameters.docs.source.code and parameters.docs.source.transform.
Current limitations
React only. Other renderers keep the legacy preview-side docgen path.
Experimental API. The feature flag, payload shapes, and snapshot layout may change.
Dev manifest routes:components.json and docs.json return 404 in dev when docgen server is on. Use the manifest HTML debugger or built Storybook for manifest inspection.
TypeScript required for RCM. Prop extraction needs a working TypeScript Language Service. Projects without TypeScript fall back to errors on the docgen payload.
Snippets
Import overrides: The legacy manifest honored a component @import JSDoc tag. Story-docs does not yet. Imports come from resolved import paths and package name rewriting only.
Complex story shapes: Stories that rely heavily on runtime composition or non-standard patterns may fail snippet extraction. The story entry will carry an error field instead of a snippet.
Formatting: Snippets are printed by recast as JSX, not run through Prettier. Formatting may differ from your project style.
Snippets do not yet update when you change Controls values, they always reflect the story’s initial args. We’re still discussing if this is the long-term plan, or if we want to port over dynamic snippets to this new architecture - feedback welcome!
Please comment if any of these limitations block your project, or if the snippet shape should change (e.g., always include the meta export, show full file context, etc.).
Request for feedback
We are committed to shipping this architecture. Your input helps us get the details right before we stabilize the API.
Please comment on:
Snippet format: Are the generated snippets useful for your team and for AI agents? What should they include or exclude?
Docgen: Does your Controls panel behave as it should, or are you seeing unexpected behavior?
Consumption: Would you consume these snapshots outside Storybook? Why?
Migration: What breaks when you enable the flag in an existing project?
Report issues with:
Your Storybook version and framework (react-vite, nextjs-vite, etc.)
A minimal reproduction or story file that fails
What you expected vs what you got (screenshots welcome)
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Docgen Server RFC
Status: In development. Available behind the
experimentalDocgenServerfeature flag for React projects in version 10.5.0 and above.Docs: features.experimentalDocgenServer
Summary
Storybook is moving docgen from the preview bundle to the dev server. This improves the component metadata produced by Storybook’s MCP and also in Storybook’s auto-generated documentation.
Component metadata (props, descriptions, argTypes) and story snippets are extracted server-side and exposed through a new architecture we call the Open Service Architecture. For now, this change is React-only, but we’re planning on expanding it to the other core frameworks soon.
This RFC is open for feedback on the docgen output and the story snippet format. It is also the place to ask questions and report issues after enabling the flag in your project.
If you try this in your project, please leave a comment with what worked, what broke, and anything that surprised you. If you know that you are experiencing an actual bug, please open an issue with a reproduction and reference it here.
Background
Today, Storybook produces similar component documentation through several separate paths:
react-docgenorreact-docgen-typescriptvia Vite/Webpack plugins).These are all different ways to compute the same data, using different analysis algorithms, leading to inaccurate and inconsistent results. Preview startup is blocked on docgen plugins, and story rendering is slower than necessary because it must compute docgen before rendering the story. MCP manifest generation can be slow because it re-extracts everything. We already built React Component Meta (RCM) for MCP, but it was not wired into the main docs UI.
The docgen server unifies these consumers into a single server-side pipeline.
How to enable
In
.storybook/main.ts:When the flag is on:
core/docgenopen service, which computes them on the server.core/story-docsopen service.experimentalCodeExamples. The story-docs service replaces it.Data pipeline
Overview
Both services register at server startup when
experimentalDocgenServeris enabled. Renderer packages contribute through preset hooks:experimental_docgenProviderexperimental_storyDocsProviderOnly
@storybook/reactships providers today, but anyone can hook into these preset properties and provide their own docgen/story-docs server side - it supports composing multiple providers together to form a single docgen result for a given component/story. If you’re feeling adventurous, you can take a look at how@storybook/reacthooks into these presets and add your own metadata. Although the API and format are still experimental and subject to change, especially as we expect to learn more from expanding the support to the other frameworks in the coming months.Extraction and caching
storybook build. The service state is shared and automatically synced across all the runtimes (server, manager, preview).Static snapshot layout
Built Storybooks write per-component files under:
Each file wraps payloads in a
{ "components": { "<id>": { ... } } }envelope so JSON Pointer refs stay stable. This is an internal construct and not a public API, and it’s not unlikely that we will change this in patch versions, but feel free to take a look anyway.Manifest index format
manifests/components.jsonbecomes a lightweight index. Each component row carries summary fields inline and$refpointers to the full payloads:{ "v": 1, "components": { "components-button--button": { "id": "components-button--button", "name": "Button", "description": "Primary action button", "docgen": { "$ref": "../services/core/docgen/components-button--button.json#/components/components-button--button" }, "stories": { "$ref": "../services/core/story-docs/components-button--button.json#/components/components-button--button" } } } }Agents and MCP tools can load components one at a time rather than parse a single large inline manifest.
core/docgenpayloadOne payload per component id:
id,name,pathdescription,summaryjsDocTagsargTypessubcomponentsreactComponentMetaerrorStory snippets and file-level imports are not in this payload. They live in
core/story-docs.Custom argTypes from CSF meta and story parameters are merged at read time in the UI, same as before.
core/story-docspayloadOne payload per component id:
id,name,pathimportstories{ id, name, snippet, description, summary, error? }errorStory snippet format
We would love feedback on this section in particular.
How snippets are generated
For each story export in a CSF file, Storybook parses the file with Babel/recast and builds a React JSX snippet that shows how the component is used. The output looks like a small React component rather than the CSF story definition.
Roughly:
() => <Button disabled>Click me</Button>. Stories with a custom render keep that JSX shape, but with args filled in so you see concrete prop values instead of{...args}orargs.label.The goal is more complete usage examples; this is not just the JSX, but an actual React component, complete with imports.
Example
Given a CSF4 story file like:
The snippet for
Disabledis a JSX usage example:For a story with a custom render that spreads args:
The snippet inlines the merged args into the JSX:
When the render function cannot be resolved (for example, an imported template), Storybook falls back to synthesizing JSX from the component name and merged args.
Snippets still support per-story customization via
parameters.docs.source.codeandparameters.docs.source.transform.Current limitations
components.jsonanddocs.jsonreturn 404 in dev when docgen server is on. Use the manifest HTML debugger or built Storybook for manifest inspection.Snippets
@importJSDoc tag. Story-docs does not yet. Imports come from resolved import paths and package name rewriting only.errorfield instead of asnippet.Please comment if any of these limitations block your project, or if the snippet shape should change (e.g., always include the meta export, show full file context, etc.).
Request for feedback
We are committed to shipping this architecture. Your input helps us get the details right before we stabilize the API.
Please comment on:
Report issues with:
react-vite,nextjs-vite, etc.)Beta Was this translation helpful? Give feedback.
All reactions