Storybook is a frontend workshop for building, testing, and documenting UI components and pages in isolation. It runs alongside your application, providing a dedicated environment where components render outside of the main app context. This enables developers to focus on hard-to-reach states, edge cases, and variations without needing to navigate through complex application flows or maintain seed data.
At its core, Storybook is an architecture for rendering components in isolation using a two-frame model: a Manager UI (sidebar, toolbar, addon panels) running in the parent frame and a Preview iframe where stories actually render. A Node.js Core Server coordinates both, handling story indexing, file watching, HMR, and live communication channels. The system is extensible through a preset-based configuration pipeline, a rich addon API, and framework-specific integrations that abstract away builder and renderer differences. Version 10.4.0-alpha.10 (at commit 245043f) is a massive TypeScript monorepo containing 5,370 files across the core engine, 22 framework integrations, 7 renderers, 2 builders, 7 addons, and supporting libraries, all managed with Yarn 4.10.3 workspaces.
This guide covers the complete architecture, configuration surface, operational procedures, security model, and developer internals needed to administer, extend, and contribute to Storybook at any scale.
1. Architecture Overview
1.1 High-Level System Diagram
┌─────────────────────────────────────────────────────────────────────┐
│ Developer's Browser │
│ │
│ ┌──────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ MANAGER (Parent) │ │ PREVIEW (iframe) │ │
│ │ │ │ │ │
│ │ ┌────────┐ ┌─────────────┐ │ │ ┌──────────────────────┐ │ │
│ │ │Sidebar │ │ Toolbar │ │ │ │ Story Rendering │ │ │
│ │ │ Tree │ │ Controls │ │ │ │ (React/Vue/Svelte/ │ │ │
│ │ └────────┘ └─────────────┘ │ │ │ HTML/Preact/WC/ │ │ │
│ │ ┌─────────────────────────┐ │ │ │ Server) │ │ │
│ │ │ Addon Panels │ │ │ └──────────────────────┘ │ │
│ │ │ (A11y, Docs, Actions, │ │ │ ┌──────────────────────┐ │ │
│ │ │ Controls, etc.) │ │ │ │ preview-api │ │ │
│ │ └─────────────────────────┘ │ │ │ (Store, Decorators, │ │ │
│ │ │ │ │ Args, Addons API) │ │ │
│ │ manager-api (state mgmt) │ │ └──────────────────────┘ │ │
│ └──────────┬───────────────────┘ └──────────┬──────────────────┘ │
│ │ PostMessage Channel │ │
│ └──────────────┬───────────────────┘ │
└────────────────────────────┼────────────────────────────────────────┘
│ WebSocket Channel
│
┌────────────────────────────┼────────────────────────────────────────┐
│ CORE SERVER (Node.js) │
│ │
│ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Story Indexer │ │ File Watcher │ │ Builder │ │
│ │ (glob → CSF │ │ (chokidar) │ │ (Vite or │ │
│ │ parse → index)│ │ │ │ Webpack 5) │ │
│ └─────────────────┘ └──────────────────┘ └──────────────────┘ │
│ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Preset System │ │ Static Files │ │ Telemetry │ │
│ │ (config merge) │ │ Serving │ │ (anonymous) │ │
│ └─────────────────┘ └──────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
1.2 Component Inventory
| Component | Package / Path | Role |
|---|---|---|
| Core Engine | code/core/ (storybook) |
Unified package containing CLI, server, manager, preview, channels, theming, telemetry |
| Manager UI | code/core/src/manager/ |
Parent-frame UI: sidebar tree, toolbar, addon panels, settings |
| Manager API | code/core/src/manager-api/ |
State management for Manager: stories index, addons registry, shortcuts, notifications |
| Preview API | code/core/src/preview-api/ |
Story rendering engine: store, decorators, args processing, addon hooks |
| Core Server | code/core/src/core-server/ |
Node.js dev server: story indexing, file watching, HMR, WebSocket channel |
| Channels | code/core/src/channels/ |
PostMessage + WebSocket transport abstraction |
| CSF | code/core/src/csf/ |
Component Story Format parser and utilities |
| CSF Tools | code/core/src/csf-tools/ |
CSF manipulation, Vitest plugin integration |
| Docs Tools | code/core/src/docs-tools/ |
ArgTypes extraction, docgen processing (TypeScript, PropTypes, Flow) |
| Theming | code/core/src/theming/ |
Theme system (light/dark themes, styled API) |
| Telemetry | code/core/src/telemetry/ |
Anonymous usage data collection |
| Types | code/core/src/types/ |
TypeScript type definitions for the entire ecosystem |
| Shared Utilities | code/core/src/shared/ |
UniversalStore, StatusStore, TestProviderStore, constants |
| Common Utilities | code/core/src/common/ |
Package managers, presets, paths, envs, file cache |
| Builder: Vite | code/builders/builder-vite/ |
Vite-based builder for Manager and Preview bundles |
| Builder: Webpack 5 | code/builders/builder-webpack5/ |
Webpack 5-based builder with HMR support |
| CLI Storybook | code/lib/cli-storybook/ |
CLI subcommands: add, upgrade, migrate, doctor, sandbox, automigrate |
| Create Storybook | code/lib/create-storybook/ |
Project initialization (storybook init) with service-based architecture |
| Codemod | code/lib/codemod/ |
Code transformation utilities for migrations |
| CSF Plugin | code/lib/csf-plugin/ |
Vite/Webpack plugin for CSF compilation |
| ESLint Plugin | code/lib/eslint-plugin/ |
ESLint rules for story files |
| Core Webpack | code/lib/core-webpack/ |
Shared Webpack utilities across builders and frameworks |
| React DOM Shim | code/lib/react-dom-shim/ |
React DOM compatibility layer across React versions |
1.3 Framework Matrix
| Framework Package | Builder | Renderer | Key Features |
|---|---|---|---|
@storybook/react-vite |
Vite | React | SWC/Babel docgen, React Fast Refresh |
@storybook/react-webpack5 |
Webpack 5 | React | Babel docgen, CRA compatibility |
@storybook/nextjs |
Webpack 5 | React | Next.js module mocking (router, image, font, navigation, headers, cache), RSC support |
@storybook/nextjs-vite |
Vite | React | Next.js module mocking via Vite plugin, Styled JSX support |
@storybook/vue3-vite |
Vite | Vue 3 | Vue SFC compilation, component-meta docgen |
@storybook/svelte-vite |
Vite | Svelte | Svelte compilation, CSF stories support |
@storybook/sveltekit |
Vite | Svelte | SvelteKit module mocking ($app/navigation, $app/stores, $app/environment) |
@storybook/angular |
Webpack 5 | Angular | Angular CLI builder integration, zone.js support, Compodoc docgen |
@storybook/html-vite |
Vite | HTML | Plain HTML/string rendering |
@storybook/preact-vite |
Vite | Preact | Preact-specific rendering |
@storybook/web-components-vite |
Vite | Web Components | Lit element support, custom elements manifest |
@storybook/react-native-web-vite |
Vite | React | React Native Web compatibility |
@storybook/ember |
Webpack 5 | Ember | Ember CLI integration |
@storybook/server-webpack5 |
Webpack 5 | Server | Server-rendered HTML stories |
1.4 Addon Inventory
| Addon | Package | Purpose |
|---|---|---|
| A11y | @storybook/addon-a11y |
Accessibility testing via axe-core integration |
| Docs | @storybook/addon-docs |
Automatic documentation generation (DocsPage, MDX, doc blocks) |
| Links | @storybook/addon-links |
Story-to-story navigation links |
| Onboarding | @storybook/addon-onboarding |
First-run guided tour with splash screen and intent survey |
| Pseudo States | @storybook/addon-pseudo-states |
CSS pseudo-state simulation (:hover, :focus, :active, etc.) |
| Themes | @storybook/addon-themes |
Theme switching via decorators (withThemeFromJSXProvider, withThemeByClassName, withThemeByDataAttribute) |
| Vitest | @storybook/addon-vitest |
Vitest integration for component testing with story reuse |
1.5 Technology Stack
| Layer | Technology | Version |
|---|---|---|
| Language | TypeScript | 5.9.3 |
| Package Manager | Yarn | 4.10.3 (Berry, PnP-capable) |
| Monorepo | Yarn Workspaces + Nx | Nx 22.6.1 |
| Primary Builder | Vite | 7.0.4 |
| Secondary Builder | Webpack | 5.x |
| Test Runner | Vitest | 4.1.0 |
| E2E Testing | Playwright | 1.58.2 |
| Linting | ESLint | 8.57.1 |
| Formatting | oxfmt | 0.41.0 |
| Bundler (internal) | esbuild | 0.27.0 |
| UI Framework | React | 18.2.0 (Manager UI) |
1.6 Data Flow: Dev Mode
1. CLI invokes `storybook dev`
└─> Core Server starts
├─> Loads presets (framework → builder → addons → user config)
├─> StoryIndexGenerator scans story files (glob matching)
│ └─> Parses CSF exports → builds index.json (v5)
├─> Builder starts (Vite dev server or Webpack dev middleware)
│ ├─> Bundles Manager UI
│ └─> Bundles Preview with story imports
└─> HTTP/WS server starts
2. Browser loads Manager UI
├─> Fetches /index.json (story index)
├─> Renders sidebar tree from index
└─> Creates PostMessage channel to Preview iframe
3. Browser loads Preview iframe
├─> preview-api initializes Store
├─> Imports story modules (lazy)
└─> Renders selected story with decorators + args
4. File change detected
├─> Builder triggers HMR
├─> StoryIndexGenerator re-indexes if story file changed
└─> Server pushes update via WebSocket → Manager updates sidebar
1.7 Data Flow: Static Build
1. CLI invokes `storybook build`
└─> Core Server starts (build mode)
├─> Loads presets
├─> StoryIndexGenerator builds full index
├─> Builder produces static bundles
│ ├─> Manager bundle (HTML + JS + CSS)
│ └─> Preview bundle (HTML + JS)
└─> Writes to output directory (default: storybook-static/)
2. Static output structure:
storybook-static/
├── index.html (Manager entry)
├── iframe.html (Preview entry)
├── index.json (Story index)
├── assets/ (JS/CSS chunks)
└── sb-addons/ (Addon assets)
2. System Requirements
2.1 Node.js
Storybook enforces strict Node.js version requirements defined in code/core/src/common/node-version.ts:
| Requirement | Version |
|---|---|
| Minimum supported | Node.js 20.19+ or Node.js 22.12+ |
| Validation | Uses semver satisfies() with MIN_SUPPORTED_NODE_VERSIONS array |
| Behavior on mismatch | Prints warning and exits |
Important
Node.js versions between 21.x and 22.11 are not supported due to missing APIs. The project requires either the 20.x LTS track (20.19+) or the 22.x track (22.12+).
2.2 Browser Support
Defined in code/package.json via the browserslist field:
| Browser | Minimum Version |
|---|---|
| Chrome | 131+ |
| Android Chrome | 131+ |
| Edge | 134+ |
| Firefox | 136+ |
| Safari | 18.3+ |
| iOS Safari | 18.3+ |
| Opera | 117+ |
2.3 Package Managers
Storybook supports the three major Node.js package managers through its JsPackageManager abstraction in code/core/src/common/js-package-manager/:
| Package Manager | Detection | Notes |
|---|---|---|
| npm | package-lock.json |
Default fallback |
| Yarn | yarn.lock |
Supports Classic (1.x) and Berry (2+/PnP) |
| pnpm | pnpm-lock.yaml, pnpm-workspace.yaml |
Workspace support |
The detection algorithm walks up the directory tree looking for lockfiles. When multiple lockfiles exist, it uses proximity (closest lockfile wins).
2.4 Framework-Specific Requirements
| Framework | Additional Requirements |
|---|---|
| Angular | Angular CLI, angular.json workspace file, zone.js |
| Next.js | Next.js 13+ (detects version via __NEXT_VERSION env var) |
| Next.js (Vite) | Next.js 13+, Vite-based builder required |
| SvelteKit | SvelteKit project structure, Vite builder |
| React Native Web | Expo or RN CLI project, Vite builder |
| Ember | Ember CLI, ember-cli-build.js |
| Vitest Addon | Vitest >= 3.0.0, MSW >= 2.0.0 (if installed), Vite-based builder only |
Note
The Vitest addon explicitly rejects Webpack-based frameworks, even for Next.js. If you use
@storybook/nextjs(Webpack), you must switch to@storybook/nextjs-viteto use the Vitest addon. It also rejects JSON workspace files, CommonJS config files (.cts,.cjs), and arrow function configs.
3. Configuration Reference
3.1 Configuration Files
Storybook configuration lives in the .storybook/ directory (configurable via --config-dir CLI flag):
| File | Purpose | Environment |
|---|---|---|
.storybook/main.js (or .ts) |
Primary configuration: stories globs, addons, framework, builder options | Node.js (server-side) |
.storybook/preview.js (or .ts) |
Story rendering config: decorators, parameters, globalTypes, loaders | Browser (preview iframe) |
.storybook/manager.js (or .ts) |
Manager UI config: theme, addon panel order, sidebar behavior | Browser (manager frame) |
Tip
TypeScript configuration files (
.storybook/main.ts,.storybook/preview.ts) are fully supported and recommended. The config is loaded viajitifor seamless TypeScript support without compilation.
3.2 Main Configuration Fields
The .storybook/main.js file exports an object with the following fields:
3.2.1 stories (required)
Glob patterns specifying where to find story files.
// .storybook/main.ts
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
};
export default config;
Each entry can be:
- A string glob —
'../src/**/*.stories.tsx' - An object with
directory,files, and optionaltitlePrefixfields
The StoryIndexGenerator resolves these globs, parses CSF exports from matching files, and builds the story index. Duplicate story IDs (same title + name combination) throw an IndexingError.
Warning
Invalid globs cause a hard error at startup. The system validates glob syntax using
glob-to-regexpand throwsError: Invalid globif the pattern cannot be compiled.
3.2.2 addons
Array of addon package names or configuration objects:
const config: StorybookConfig = {
addons: [
'@storybook/addon-a11y',
'@storybook/addon-docs',
{
name: '@storybook/addon-vitest',
options: { /* addon-specific options */ },
},
],
};
Addons are resolved in order. Each addon can export a preset entry point that contributes to the configuration pipeline.
3.2.3 framework (required)
Specifies the framework integration package:
const config: StorybookConfig = {
framework: {
name: '@storybook/react-vite',
options: {
// Framework-specific options
},
},
};
Caution
A missing
frameworkfield throwsMissingFrameworkFieldError. An invalid framework name throwsInvalidFrameworkNameError. If the framework module cannot be evaluated (e.g., missing dependency),CouldNotEvaluateFrameworkErroris thrown.
3.2.4 staticDirs
Directories to serve as static files:
const config: StorybookConfig = {
staticDirs: [
'../public',
{ from: '../assets', to: '/static' },
],
};
Warning
Using both
staticDirsin main config and the-sCLI flag simultaneously throwsConflictingStaticDirConfigError. Choose one method.
3.2.5 core
Core engine configuration:
const config: StorybookConfig = {
core: {
disableTelemetry: true, // Opt out of anonymous telemetry
enableCrashReports: false, // Disable crash report sending
builder: 'webpack5', // Override builder (usually set by framework)
},
};
3.2.6 features
Feature flags for enabling/disabling specific behaviors:
const config: StorybookConfig = {
features: {
// Feature flags vary by version
},
};
3.2.7 docs
Documentation configuration:
const config: StorybookConfig = {
docs: {
defaultName: 'Docs', // Name for auto-generated docs entries
},
};
3.2.8 refs
Composition references to other Storybook instances:
const config: StorybookConfig = {
refs: {
'design-system': {
title: 'Design System',
url: 'https://design-system.example.com',
},
},
};
3.2.9 typescript
TypeScript configuration for docgen and type checking:
const config: StorybookConfig = {
typescript: {
check: false, // Enable type checking
reactDocgen: 'react-docgen-typescript', // or 'react-docgen'
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => !prop.parent?.fileName.includes('node_modules'),
},
},
};
3.2.10 build
Build optimization settings:
const config: StorybookConfig = {
build: {
test: {
disableBlocks: false, // Disable doc blocks in test builds
disabledAddons: [], // Addons to skip in test builds
disableMDXEntries: false, // Skip MDX processing in test builds
disableAutoDocs: false, // Disable auto-docs generation
disableDocgen: false, // Disable prop extraction
disableSourcemaps: false, // Disable sourcemap generation
disableTreeShaking: false, // Disable tree shaking
},
},
};
3.2.11 env
Custom environment variables passed to the browser:
const config: StorybookConfig = {
env: (config) => ({
...config,
MY_VAR: 'value',
}),
};
3.3 Preview Configuration
The .storybook/preview.js file configures how stories render:
// .storybook/preview.ts
import type { Preview } from '@storybook/react';
const preview: Preview = {
decorators: [
// Wraps every story
(Story) => (
<div style={{ padding: '1rem' }}>
<Story />
</div>
),
],
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
layout: 'centered',
},
globalTypes: {
theme: {
description: 'Global theme',
toolbar: {
title: 'Theme',
icon: 'circlehollow',
items: ['light', 'dark'],
dynamicTitle: true,
},
},
},
loaders: [
// Async data loading before story render
async () => ({ data: await fetchData() }),
],
tags: ['autodocs'], // Enable auto-docs for all stories
};
export default preview;
3.4 Manager Configuration
The .storybook/manager.js file customizes the Manager UI:
// .storybook/manager.ts
import { addons } from 'storybook/internal/manager-api';
import { create } from 'storybook/internal/theming';
addons.setConfig({
theme: create({
base: 'dark',
brandTitle: 'My Design System',
brandUrl: 'https://example.com',
brandImage: '/logo.svg',
brandTarget: '_self',
}),
sidebar: {
showRoots: true,
collapsedRoots: ['other'],
},
toolbar: {
fullscreen: { hidden: false },
zoom: { hidden: false },
},
panelPosition: 'bottom', // 'bottom' | 'right'
enableShortcuts: true,
showPanel: true,
showToolbar: true,
});
3.5 Environment Variables Reference
All environment variables detected in the source code, grouped by purpose:
Core Runtime Variables
| Variable | Purpose | Source |
|---|---|---|
NODE_ENV |
Standard environment flag (development, production, test) |
code/core/src/common/utils/envs.ts |
STORYBOOK |
Set to 'true' when running inside Storybook |
code/core/src/common/utils/envs.ts |
STORYBOOK_PROJECT_ROOT |
Override the auto-detected project root directory | code/core/src/common/utils/paths.ts |
NODE_PATH |
Additional module resolution paths | code/core/src/common/utils/envs.ts |
CI |
Indicates CI environment; affects prompts and interactivity | vitest.config.ts |
DEBUG |
Enable debug logging | scripts/tasks/e2e-tests-build.ts |
Builder and Dev Server Variables
| Variable | Purpose | Source |
|---|---|---|
INSPECT |
Enable Node.js inspector for debugging Vitest | code/vitest.config.storybook.ts |
PORT |
Override default server port | test-storybooks/server-kitchen-sink/server.js |
STORYBOOK_SERVE_PORT |
Override the Storybook dev server port | scripts/tasks/dev.ts |
NODE_OPTIONS |
Node.js runtime flags (e.g., --max_old_space_size) |
scripts/tasks/sandbox-parts.ts |
PUBLIC_URL |
Public URL for CRA-based builds | code/presets/create-react-app/src/index.ts |
Next.js Framework Variables
| Variable | Purpose | Source |
|---|---|---|
__NEXT_VERSION |
Auto-detected Next.js version | code/frameworks/nextjs/src/utils.ts |
__NEXT_PRIVATE_RENDER_WORKER |
Next.js render worker flag | code/frameworks/nextjs/src/utils.ts |
__NEXT_RUNTIME_CONFIG |
Next.js runtime config injection | code/frameworks/nextjs/src/config/preview.ts |
__NEXT_NEW_LINK_BEHAVIOR |
Next.js Link component behavior flag | code/frameworks/nextjs/src/config/webpack.ts |
Testing and CI Variables
| Variable | Purpose | Source |
|---|---|---|
VITEST |
Set to 'true' when running under Vitest |
code/core/src/shared/utils/module.ts |
STORYBOOK_URL |
Storybook URL for Playwright tests | code/playwright.config.ts |
STORYBOOK_TEMPLATE_NAME |
Template name for Playwright test runs | code/playwright.config.ts |
PLAYWRIGHT_JUNIT_OUTPUT_NAME |
JUnit output file name for Playwright | code/playwright.config.ts |
STORYBOOK_CLI_SKIP_PLAYWRIGHT_INSTALLATION |
Skip Playwright browser installation during addon-vitest setup | code/core/src/cli/AddonVitestService.ts |
Internal / CI Infrastructure Variables
| Variable | Purpose | Source |
|---|---|---|
GITHUB_ACTIONS |
Detects GitHub Actions CI | scripts/sandbox/generate.ts |
CLEANUP_SANDBOX_NODE_MODULES |
Clean node_modules after sandbox generation | scripts/sandbox/generate.ts |
STORYBOOK_SANDBOX_GENERATE |
Trigger sandbox generation | scripts/sandbox/generate.ts |
STORYBOOK_SANDBOX_DIR |
Sandbox directory path for e2e tests | code/e2e-tests/addon-mcp.spec.ts |
STORYBOOK_SANDBOX_ROOT |
Root directory for sandboxes | scripts/utils/constants.ts |
IN_STORYBOOK_SANDBOX |
Indicates running inside a sandbox | code/lib/cli-storybook/src/sandbox.ts |
STORYBOOK_INIT_EMPTY_TYPE |
Project type for empty storybook init |
code/lib/create-storybook/src/scaffold-new-project.ts |
STORYBOOK_TYPE |
Storybook type for e2e tests | code/e2e-tests/addon-mcp.spec.ts |
STORYBOOK_NX_CLOUD_AGENT |
Nx Cloud agent flag | scripts/utils/yarn.ts |
PREVIEW_URL |
Preview URL for standalone preview test | test-storybooks/standalone-preview/addPreview.ts |
GCP_CREDENTIALS |
GCP credentials for benchmark uploads | scripts/bench/bench-packages.ts |
CIRCLE_BRANCH |
CircleCI branch name | scripts/bench/bench-packages.ts |
CIRCLE_SHA1 |
CircleCI commit SHA | scripts/bench/bench-packages.ts |
4. Deployment & Scaling
4.1 Static Build Deployment
Storybook produces a fully static site that can be hosted on any static file server:
# Build static Storybook
npx storybook build
# Output goes to storybook-static/ by default
# Override with --output-dir or -o flag
npx storybook build -o docs/storybook
The output directory structure:
storybook-static/
├── index.html # Manager entry point
├── iframe.html # Preview entry point
├── index.json # Story index (v5 format)
├── project.json # Project metadata
├── assets/ # Bundled JS/CSS
├── sb-addons/ # Addon manager entries
├── sb-manager/ # Manager bundle
├── sb-preview/ # Preview runtime
└── sb-common-assets/ # Shared assets (fonts, icons)
Deployment Targets
| Platform | Method |
|---|---|
| Netlify | Publish directory: storybook-static/ |
| Vercel | Build command: npx storybook build, output: storybook-static/ |
| GitHub Pages | Use GitHub Actions to build and deploy |
| AWS S3 + CloudFront | Upload storybook-static/ to S3, configure CloudFront for SPA routing |
| Nginx | Serve storybook-static/ with try_files $uri $uri/ /index.html |
| Docker | Multi-stage build: build stage runs storybook build, serve stage uses nginx |
Note
When deploying to a subdirectory (e.g.,
/docs/storybook/), there is no built-in base path configuration. The build output assumes it is served from the root. For subdirectory deployment, use a reverse proxy to rewrite paths.
4.2 CI/CD Integration
GitHub Actions Example
name: Storybook
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm ci
- run: npx storybook build
- uses: actions/upload-artifact@v4
with:
name: storybook
path: storybook-static/
Test Integration in CI
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
# Run Vitest with Storybook stories
- run: npx vitest run --project storybook
# Or run Storybook test runner
- run: npx storybook build && npx concurrently -k \
"npx http-server storybook-static -p 6006" \
"npx wait-on http://localhost:6006 && npx test-storybook"
4.3 Chromatic Integration
Chromatic provides visual regression testing and Storybook hosting:
# Install
npm install --save-dev chromatic
# Run visual tests
npx chromatic --project-token=<token>
# From pre-built Storybook
npx storybook build
npx chromatic --storybook-build-dir storybook-static --exit-zero-on-changes
The monorepo uses this pattern internally:
{
"scripts": {
"storybook:ui:chromatic": "chromatic --storybook-build-dir storybook-static --exit-zero-on-changes --exit-once-uploaded"
}
}
4.4 Storybook Composition
Multiple Storybook instances can be composed into a single UI using refs:
// .storybook/main.ts
const config: StorybookConfig = {
refs: {
'design-system': {
title: 'Design System',
url: 'https://design-system.example.com',
},
'shared-components': {
title: 'Shared Components',
url: 'https://shared.example.com',
versions: {
'1.0': 'https://v1.shared.example.com',
'2.0': 'https://v2.shared.example.com',
},
},
},
};
The Manager API's stories.ts module handles composition by fetching and merging index.json from referenced Storybooks. It validates the version format and throws Composition: Missing stories.json version if the remote index lacks version information.
4.5 Embedding Storybook
Stories can be embedded in external documentation via the iframe URL pattern:
<iframe
src="https://storybook.example.com/iframe.html?id=components-button--primary&viewMode=story"
width="100%"
height="400"
></iframe>
URL parameters:
id— Story ID intitle--nameformatviewMode—storyordocsargs— URL-encoded args overrideglobals— URL-encoded globals override
5. Operations
5.1 CLI Commands
The Storybook CLI (storybook or sb binary) dispatches to these subcommands:
| Command | Purpose |
|---|---|
storybook dev |
Start development server with HMR |
storybook build |
Produce static build for deployment |
storybook init |
Initialize Storybook in a project (runs create-storybook) |
storybook add <addon> |
Install and configure an addon |
storybook upgrade |
Upgrade Storybook to latest version with automigrations |
storybook migrate <migration> |
Run a specific codemod migration |
storybook doctor |
Diagnose common configuration issues |
storybook sandbox |
Create a sandbox project for testing |
storybook automigrate |
Run all applicable automigrations |
Dev Server Options
storybook dev \
--port 6006 \ # Dev server port (default: 6006)
--host 0.0.0.0 \ # Bind address
--config-dir .storybook \ # Config directory
--static-dir public \ # Static file directories
--no-open \ # Don't open browser
--ci \ # CI mode (no interactivity)
--quiet \ # Suppress output
--debug-webpack \ # Enable webpack debug logging
--preview-url <url> # Use external preview
Build Options
storybook build \
--output-dir storybook-static \ # Output directory
--config-dir .storybook \ # Config directory
--quiet \ # Suppress output
--stats-json \ # Generate webpack stats
--test # Optimize for test environment
5.2 Upgrading Storybook
The upgrade command handles version upgrades with automatic code migrations:
# Upgrade to latest
npx storybook upgrade
# Upgrade to specific version
npx storybook upgrade --version 10.0.0
# Dry run (show what would change)
npx storybook upgrade --dry-run
# Skip automigrations
npx storybook upgrade --skip-automigrations
Caution
Attempting to downgrade (upgrade to a lower version) throws
UpgradeStorybookToLowerVersionError. If the current version cannot be determined,UpgradeStorybookUnknownCurrentVersionErroris thrown.
The upgrade process:
- Detects current Storybook version
- Checks for blockers (incompatible configurations) via the autoblock system
- Runs applicable automigrations from
code/lib/cli-storybook/src/automigrate/fixes/ - Updates package versions
- Installs dependencies
5.3 Addon Management
Adding Addons
# Auto-install and configure
npx storybook add @storybook/addon-a11y
# The add command:
# 1. Resolves the addon package version
# 2. Installs the package
# 3. Updates .storybook/main.js addons array
# 4. Runs postinstall hooks (some addons have them)
If no version can be found for an addon, the system throws: No version found for ${addonName}.
Addon Architecture
Addons in Storybook 10 use the definePreviewAddon pattern:
// Addon entry point pattern
import { definePreviewAddon } from 'storybook/internal/csf';
import * as addonAnnotations from './preview';
import type { MyAddonTypes } from './types';
export default () => definePreviewAddon<MyAddonTypes>(addonAnnotations);
Each addon can export:
preset— Server-side configurationmanager— Manager UI panels/toolbar itemspreview— Preview decorators/parameterspostinstall— Setup script run after installation
5.4 The doctor Command
Diagnoses common issues:
npx storybook doctor
Checks include:
- Duplicate dependencies
- Version mismatches between Storybook packages
- Framework detection issues
- Builder compatibility
- Missing peer dependencies
5.5 Monitoring and Health
Story Index Health
The StoryIndexGenerator provides statistics about the indexed stories:
// Stats tracked per index generation
{
beforeEach: number, // Stories using beforeEach
factory: number, // Stories using factory pattern
globals: number, // Stories using globals
loaders: number, // Stories using loaders
moduleMock: number, // Stories using module mocking
mount: number, // Stories using mount
play: number, // Stories using play functions
render: number, // Stories using custom render
storyFn: number, // Stories using story functions
tags: number, // Stories using tags
}
Telemetry
Storybook collects anonymous usage telemetry (opt-out via core.disableTelemetry). The telemetry module at code/core/src/telemetry/ tracks:
- Project type and framework
- Addons in use
- Builder type
- Story count and feature usage
- Error categories and codes
5.6 Troubleshooting
Common Issues and Solutions
| Symptom | Likely Cause | Solution |
|---|---|---|
| Infinite loading state | Dynamic import between story files (#28382) | Avoid circular dynamic imports between CSF files |
| "Couldn't find any stories" | Incorrect stories glob in main config |
Verify glob patterns match your file structure |
| Duplicate story IDs | Two stories with same title + name | Rename one story or use unique titles |
| "Missing framework field" | Missing framework in main config |
Add framework field to .storybook/main.js |
| "Could not evaluate framework" | Framework package not installed | Run npm install @storybook/<framework> |
| WebSocket connection fails | Origin/token validation failure | Check for proxy/CDN stripping headers |
| "Preset load error" | Broken addon or preset | Check the addon is compatible with your Storybook version |
| Blank preview iframe | Builder compilation error | Check terminal for build errors |
| Storybook stuck at startup | Port conflict or process lock | Kill existing processes on port 6006 |
| "Re-export stories not working" | CSF re-exports need proper syntax (#32561) | Use named re-exports, not barrel files |
Stuck Job Detection
For automated environments, the StoryIndexGenerator implements timeout detection. If story indexing takes excessively long, it is typically due to:
- Very large codebases with thousands of story files
- Complex glob patterns scanning too many directories
- CSF parsing failures on malformed files
6. Performance
6.1 Builder Selection: Vite vs Webpack 5
| Aspect | Vite Builder | Webpack 5 Builder |
|---|---|---|
| Dev startup | Fast (no bundling, native ESM) | Slower (full bundle required) |
| HMR speed | Near-instant | Moderate (rebuild affected modules) |
| Build output | Rollup-based, good tree shaking | Comprehensive, mature optimization |
| Plugin ecosystem | Growing, Vite/Rollup plugins | Vast, mature ecosystem |
| Memory usage | Lower | Higher (full dependency graph in memory) |
| Best for | Most projects, especially new ones | Legacy projects, CRA, complex webpack configs |
| Framework support | React, Vue, Svelte, HTML, Preact, Web Components, Next.js (Vite) | React, Angular, Next.js, Ember, Server |
Tip
For new projects, always prefer Vite-based frameworks. The Vite builder provides significantly faster dev startup and HMR. Only use Webpack if your framework requires it (Angular, Ember) or you have extensive custom Webpack configuration.
6.2 Vite Builder Architecture
The Vite builder (code/builders/builder-vite/src/) implements:
Plugins pipeline (code/builders/builder-vite/src/plugins/):
vite-mock— Module mocking infrastructure for test storiesvite-inject-mocker— Mocker injection into preview- CSF plugin integration via
@storybook/csf-plugin - External globals plugin for shared dependencies
- Code generator plugin for virtual story imports
Module graph tracking (build-module-graph.ts):
- Builds a dependency graph from Vite's module graph
- Used for change detection and selective rebuilds
- Tracks which stories are affected by a file change
Build optimizations:
- Lazy compilation of story modules (only compile what's viewed)
- Source map generation (controllable via
build.test.disableSourcemaps) - Tree shaking (controllable via
build.test.disableTreeShaking)
6.3 Webpack 5 Builder Architecture
The Webpack 5 builder (code/builders/builder-webpack5/src/) provides:
- Custom loaders for story files
DependencyCollectorplugin for tracking story dependencies- Webpack stats generation for bundle analysis
- Lazy compilation support via
experiments.lazyCompilation
The builder throws WebpackMissingStatsError if stats are unavailable after build, and WebpackInvocationError or WebpackCompilationError for build-time failures.
6.4 Story Indexing Performance
The StoryIndexGenerator (code/core/src/core-server/utils/StoryIndexGenerator.ts) is the critical path for startup performance:
- File matching cache —
clearFindMatchingFilesCache()static method for cache management - Incremental re-indexing — Only re-processes changed files on HMR
- Parallel processing — Processes multiple specifiers concurrently
- Deduplication — Detects and reports duplicate story IDs early
For large codebases (1000+ stories), optimize by:
- Using specific glob patterns instead of overly broad ones
- Splitting stories into separate directories with targeted specifiers
- Using
titlePrefixto avoid ID collisions - Enabling
build.test.disableAutoDocsin CI builds if docs are not needed
6.5 Build Optimization Configuration
// .storybook/main.ts — optimized for CI/test builds
const config: StorybookConfig = {
build: {
test: {
disableBlocks: true, // Skip doc blocks (faster builds)
disableMDXEntries: true, // Skip MDX processing
disableAutoDocs: true, // No auto-generated docs pages
disableDocgen: true, // Skip prop extraction
disableSourcemaps: true, // No sourcemaps (smaller output)
disableTreeShaking: false, // Keep tree shaking enabled
},
},
};
6.6 Memory Management
For large monorepos, Node.js may run out of memory. The Storybook project itself uses:
NODE_OPTIONS="--max_old_space_size=4096" storybook dev
NODE_OPTIONS="--max_old_space_size=5120" storybook build
7. Security
7.1 WebSocket Origin and Token Validation
The Core Server validates WebSocket connections in code/core/src/core-server/utils/get-server-channel.ts:
// Origin validation
if (!isValidOrigin(origin)) {
throw new Error('Invalid websocket origin');
}
// Token validation
if (!isValidToken(token)) {
throw new Error('Invalid websocket token');
}
The ServerChannelTransport class wraps the WebSocket connection and enforces both origin and token checks before accepting connections. This prevents cross-origin WebSocket hijacking.
Important
When running Storybook behind a reverse proxy, ensure the proxy passes the
Originheader correctly. Stripping or rewriting theOriginheader will cause WebSocket connections to fail with "Invalid websocket origin".
7.2 Content Security Policy (CSP)
Storybook's two-frame architecture (Manager + Preview iframe) has CSP implications:
- The Preview iframe renders user components that may include inline styles, scripts, and dynamic content
- The Manager communicates with the Preview via
postMessage - The dev server serves from
localhostwith dynamically generated ports
For strict CSP environments:
- Allow
frame-src 'self'for the Preview iframe - Allow
connect-src 'self' ws:for WebSocket connections - Consider
unsafe-inlinefor styles if using CSS-in-JS in stories - Static builds may need adjusted CSP headers depending on hosting
7.3 iframe Sandboxing
The Preview renders in an <iframe> element. This provides:
- DOM isolation between Manager and component rendering
- Style isolation (Manager styles don't bleed into stories)
- Script isolation (story errors don't crash the Manager)
The iframe loads iframe.html which bootstraps the Preview runtime. Stories are rendered within this sandboxed context.
7.4 Dependency Security
The monorepo pins critical dependencies via resolutions in the root package.json:
{
"resolutions": {
"@babel/runtime": "latest",
"@babel/traverse": "latest",
"@types/node": "^22.19.1",
"esbuild": "^0.27.0",
"typescript": "^5.9.3"
}
}
Warning
When using
storybook initorstorybook add, the CLI downloads packages from npm. In air-gapped environments, configure your npm registry to use an internal mirror. The CLI throwsFailed to download tarball from ${url}if package downloads fail.
7.5 Telemetry Data
Anonymous telemetry can be disabled:
// .storybook/main.ts
const config: StorybookConfig = {
core: {
disableTelemetry: true,
enableCrashReports: false,
},
};
Or via environment variable:
STORYBOOK_DISABLE_TELEMETRY=1 storybook dev
The telemetry module (code/core/src/telemetry/) collects non-PII data: project type, framework, addons, story counts, and error codes. No source code, story content, or file paths are transmitted.
8. Developer Internals
8.1 Repository Structure
storybookjs/storybook/
├── code/ # All publishable source packages
│ ├── core/ # Unified core engine (THE storybook package)
│ │ ├── src/
│ │ │ ├── cli/ # CLI dispatcher, AddonVitestService, globalSettings
│ │ │ ├── core-server/ # Dev server, story indexing, HMR, server channel
│ │ │ │ ├── utils/ # StoryIndexGenerator, IndexingError, server-channel
│ │ │ │ ├── presets/ # Common preset (csfIndexer)
│ │ │ │ ├── stores/ # Server-side state stores
│ │ │ │ └── change-detection/ # File change detection for HMR
│ │ │ ├── manager/ # Manager UI application
│ │ │ │ ├── components/ # Sidebar, preview, toolbar, panels, notifications
│ │ │ │ ├── settings/ # Settings pages, shortcuts, about, checklist
│ │ │ │ ├── utils/ # UI utilities
│ │ │ │ └── hooks/ # React hooks for Manager
│ │ │ ├── manager-api/ # State management
│ │ │ │ ├── lib/ # AddonStore, stories, request-response
│ │ │ │ ├── modules/ # API modules
│ │ │ │ └── stores/ # Persistent stores
│ │ │ ├── preview-api/ # Story rendering engine
│ │ │ │ └── modules/
│ │ │ │ ├── store/ # Story store, CSF processing
│ │ │ │ ├── preview-web/ # Web preview, docs context, render pipeline
│ │ │ │ └── addons/ # Addon registration API
│ │ │ ├── channels/ # Communication layer
│ │ │ │ ├── postmessage/ # iframe PostMessage transport
│ │ │ │ └── websocket/ # WebSocket transport
│ │ │ ├── common/ # Shared server-side utilities
│ │ │ │ ├── utils/ # envs, paths, glob, file-cache, HandledError, CLI
│ │ │ │ └── js-package-manager/ # npm/yarn/pnpm abstraction
│ │ │ ├── csf/ # Component Story Format parser
│ │ │ ├── csf-tools/ # CSF manipulation, Vitest plugin
│ │ │ ├── docs-tools/ # ArgTypes extraction, docgen
│ │ │ │ └── argTypes/ # TypeScript, PropTypes, Flow docgen
│ │ │ ├── theming/ # Theme system (light/dark, styled API)
│ │ │ ├── types/ # TypeScript type definitions
│ │ │ ├── telemetry/ # Usage telemetry
│ │ │ ├── instrumenter/ # Test instrumentation for play functions
│ │ │ ├── shared/ # Universal store, status store, constants
│ │ │ │ ├── universal-store/ # Cross-frame state synchronization
│ │ │ │ ├── status-store/ # Story status tracking
│ │ │ │ ├── test-provider-store/ # Test provider state
│ │ │ │ ├── checklist-store/ # Onboarding checklist state
│ │ │ │ └── constants/ # Tags, shared constants
│ │ │ ├── builder-manager/ # Manager bundle builder
│ │ │ ├── components/ # Shared UI components (design system)
│ │ │ ├── actions/ # Actions addon (built-in)
│ │ │ ├── backgrounds/ # Backgrounds addon (built-in)
│ │ │ ├── controls/ # Controls addon (built-in)
│ │ │ ├── highlight/ # Highlight addon (built-in)
│ │ │ ├── measure/ # Measure addon (built-in)
│ │ │ ├── outline/ # Outline addon (built-in)
│ │ │ ├── viewport/ # Viewport addon (built-in)
│ │ │ ├── toolbar/ # Toolbar system
│ │ │ ├── router/ # Client-side routing
│ │ │ ├── test/ # Test utilities
│ │ │ ├── component-testing/ # Component testing utilities
│ │ │ ├── mocking-utils/ # Module mocking utilities
│ │ │ ├── core-events/ # Event constants and data types
│ │ │ ├── preview/ # Preview entry point, globals
│ │ │ ├── client-logger/ # Browser-side logging
│ │ │ ├── node-logger/ # Node-side logging and prompts
│ │ │ ├── babel/ # Babel configuration
│ │ │ ├── storybook-error.ts # Base StorybookError class
│ │ │ ├── manager-errors.ts # Manager error definitions
│ │ │ ├── preview-errors.ts # Preview error definitions
│ │ │ └── server-errors.ts # Server error definitions
│ │ ├── assets/ # Static assets (browser, server, docs)
│ │ ├── scripts/ # Internal build scripts
│ │ └── template/ # Template stories for built-in addons
│ ├── addons/ # Official addon packages (7)
│ ├── builders/ # Build system adapters (2)
│ ├── frameworks/ # Framework integrations (14+)
│ ├── renderers/ # View-layer adapters (7)
│ ├── lib/ # Supporting libraries (7)
│ ├── presets/ # Framework presets (3)
│ ├── e2e-tests/ # End-to-end test suites
│ ├── sandbox/ # Sandbox configurations
│ └── __mocks__/ # Global test mocks
├── scripts/ # Monorepo tooling
│ ├── tasks/ # Build, dev, check, bench tasks
│ ├── sandbox/ # Sandbox generation
│ ├── ci/ # CI pipeline utilities
│ ├── bench/ # Performance benchmarking
│ ├── check/ # Package validation
│ ├── ecosystem-ci/ # Ecosystem CI integration
│ ├── snippets/ # Documentation snippet extraction
│ └── utils/ # Shared script utilities
├── docs/ # Documentation source (markdown)
│ ├── get-started/ # Getting started guides
│ ├── writing-stories/ # Story authoring docs
│ ├── writing-tests/ # Testing integration docs
│ ├── writing-docs/ # Documentation authoring
│ ├── configure/ # Configuration reference
│ ├── sharing/ # Publishing and embedding
│ ├── addons/ # Addon development docs
│ ├── contribute/ # Contribution guides
│ ├── api/ # API reference
│ ├── builders/ # Builder docs
│ ├── essentials/ # Essential addon docs
│ └── ai/ # AI/MCP integration docs
├── test-storybooks/ # Test fixture projects
│ ├── ember-cli/ # Ember test project
│ ├── server-kitchen-sink/ # Server renderer test project
│ ├── yarn-pnp/ # Yarn PnP test project
│ ├── external-docs/ # External docs embedding test
│ ├── standalone-preview/ # Standalone preview test
│ └── portable-stories-kitchen-sink/ # Portable stories tests
├── CONTRIBUTING/ # Contributor documentation
├── package.json # Root workspace configuration
└── vitest.config.ts # Root Vitest configuration
8.2 Architecture Deep Dive: Manager-Channel-Preview
Communication Flow
Manager Frame Preview iframe
┌──────────────┐ ┌──────────────┐
│ manager-api │ │ preview-api │
│ │ PostMessage │ │
│ AddonStore │◄───Channel────►│ Store │
│ Stories │ │ Decorators │
│ Shortcuts │ │ Args │
│ Notifications│ │ Loaders │
└──────┬───────┘ └──────────────┘
│
│ WebSocket
│
┌──────┴───────┐
│ Core Server │
│ │
│ StoryIndex │
│ FileWatcher │
│ Builder │
└──────────────┘
Channel abstraction (code/core/src/channels/):
The channel system provides a unified event bus across frame boundaries:
// Channel interface (simplified)
interface Channel {
addListener(type: string, listener: Function): void;
removeListener(type: string, listener: Function): void;
emit(type: string, ...args: any[]): void;
on(type: string, listener: Function): void;
off(type: string, listener: Function): void;
}
Two transport implementations:
- PostMessage (
channels/postmessage/) — Manager-to-Preview communication viawindow.postMessage - WebSocket (
channels/websocket/) — Server-to-Manager communication via persistent WebSocket
The ServerChannelTransport class handles server-side WebSocket connections with origin and token validation.
Manager API Modules
The manager-api (code/core/src/manager-api/) organizes state into modules:
| Module | State Managed |
|---|---|
stories |
Story index, story selection, composition refs |
addons |
Registered panels, tools, sidebar items |
shortcuts |
Keyboard shortcut bindings |
notifications |
Toast notifications queue |
settings |
User preferences |
layout |
Panel position, sidebar visibility |
The AddonStore class (code/core/src/manager-api/lib/addons.ts) provides the registration API:
class AddonStore {
// Register addon panels, tools, etc.
add(name: string, addon: Addon): void;
// Get channel for event communication
getChannel(): Channel;
// Set configuration
setConfig(config: Config): void;
}
Preview API Rendering Pipeline
The Preview API (code/core/src/preview-api/) orchestrates story rendering:
1. Story Selection (via channel event or URL change)
2. Story Loading (import CSF module, resolve story config)
3. Args Processing (merge default args, URL args, control overrides)
4. Decorator Chain (global → component → story decorators)
5. Loader Execution (async data fetching before render)
6. renderToCanvas() (framework-specific render function)
7. Play Function (interaction testing, if defined)
The store module (preview-api/modules/store/) maintains:
- CSF file cache
- Processed story entries
- Args state per story
- Global state
8.3 Error System
Storybook uses a structured error system based on the StorybookError base class (code/core/src/storybook-error.ts):
class StorybookError extends Error {
name: string; // Error class name
category: string; // Category code
code: number; // Numeric code within category
documentation?: string; // Link to relevant docs
message: string; // Human-readable description
}
Error Categories
Manager Errors (code/core/src/manager-errors.ts):
| Category | Code | Error Class | Description |
|---|---|---|---|
MANAGER_UI |
1 | ProviderDoesNotExtendBaseProviderError |
Custom Provider doesn't extend base |
MANAGER_UNCAUGHT |
1 | UncaughtManagerError |
Unhandled Manager error wrapper |
MANAGER_API |
1 | StatusTypeIdMismatchError |
Status type ID mismatch in store |
Preview Errors (code/core/src/preview-errors.ts):
| Category | Code | Error Class | Description |
|---|---|---|---|
PREVIEW_API |
1 | MissingStoryAfterHmrError |
Story not found after HMR |
PREVIEW_API |
2 | ImplicitActionsDuringRendering |
Deprecated implicit action args |
PREVIEW_API |
3 | CalledExtractOnStoreError |
Extract called without caching |
PREVIEW_API |
4 | MissingRenderToCanvasError |
Framework missing renderToCanvas |
PREVIEW_API |
5 | CalledPreviewMethodBeforeInitializationError |
Method called before init |
PREVIEW_API |
6 | StoryIndexFetchError |
Failed to fetch /index.json |
PREVIEW_API |
7 | MdxFileWithNoCsfReferencesError |
MDX without CSF references |
PREVIEW_API |
8 | EmptyIndexError |
No stories found |
PREVIEW_API |
9 | NoStoryMatchError |
Story specifier didn't match |
PREVIEW_API |
10 | MissingStoryFromCsfFileError |
Story missing from imported CSF |
PREVIEW_API |
11 | StoryStoreAccessedBeforeInitializationError |
Store access before ready |
PREVIEW_API |
12 | MountMustBeDestructuredError |
Mount not destructured in play function |
PREVIEW_API |
14 | NoRenderFunctionError |
No render function for story |
PREVIEW_API |
15 | NoStoryMountedError |
Mount destructured but not called |
PREVIEW_API |
16 | StatusTypeIdMismatchError |
Status type ID mismatch |
FRAMEWORK_NEXTJS |
1 | NextJsSharpError |
Missing sharp for AVIF images |
FRAMEWORK_NEXTJS |
2 | NextjsRouterMocksNotAvailable |
Router mocks not created yet |
DOCS_TOOLS |
1 | UnknownArgTypesError |
ArgType generation failure |
BLOCKS |
1 | InvalidBlockOfPropError |
of={undefined} in doc block |
ADDON_VITEST |
1 | UnsupportedViewportDimensionError |
Unsupported viewport unit |
ADDON_A11Y |
1 | ElementA11yParameterError |
Deprecated element parameter |
Server Errors (code/core/src/server-errors.ts):
| Category | Code | Error Class | Description |
|---|---|---|---|
CLI |
various | NxProjectDetectedError |
Nx project requires different upgrade path |
CLI_INIT |
various | GenerateNewProjectOnInitError |
Failed to scaffold new project |
CORE-SERVER |
various | MissingFrameworkFieldError |
No framework field in config |
CORE-SERVER |
various | InvalidFrameworkNameError |
Invalid framework package name |
CORE-SERVER |
various | CouldNotEvaluateFrameworkError |
Framework module evaluation failed |
CORE-SERVER |
various | ConflictingStaticDirConfigError |
Both staticDirs and -s used |
CORE-SERVER |
various | InvalidStoriesEntryError |
Invalid stories glob entry |
CORE-SERVER |
various | CriticalPresetLoadError |
Preset failed to load |
CORE-SERVER |
various | MissingBuilderError |
No builder configured |
CORE-SERVER |
various | MainFileMissingError |
.storybook/main.js not found |
CORE-SERVER |
various | MainFileEvaluationError |
Main config evaluation failed |
BUILDER-WEBPACK5 |
various | WebpackMissingStatsError |
No stats after build |
BUILDER-WEBPACK5 |
various | WebpackInvocationError |
Webpack invocation failed |
BUILDER-WEBPACK5 |
various | WebpackCompilationError |
Webpack compilation error |
FRAMEWORK_ANGULAR |
various | MissingAngularJsonError |
angular.json not found |
FRAMEWORK_ANGULAR |
various | AngularLegacyBuildOptionsError |
Legacy build options |
FRAMEWORK_NEXTJS |
various | GoogleFontsDownloadError |
Google Fonts download failed |
FRAMEWORK_NEXTJS |
various | GoogleFontsLoadingError |
Google Fonts loading failed |
FRAMEWORK_SVELTE |
various | SvelteViteWithSvelteKitError |
svelte-vite used in SvelteKit project |
CLI_UPGRADE |
various | UpgradeStorybookToLowerVersionError |
Attempted downgrade |
CLI_UPGRADE |
various | UpgradeStorybookUnknownCurrentVersionError |
Unknown current version |
CLI_AUTOMIGRATE |
various | AutomigrateError |
Automigration failed |
BUILDER_VITE |
various | NoStatsForViteDevError |
Stats not available in Vite dev |
BUILDER_VITE |
various | ViteModuleGraphSubscriptionError |
Module graph subscription failed |
Each error includes a numeric code used for:
- Telemetry tracking (error frequency by category + code)
- Documentation links (linking to specific troubleshooting pages)
- Machine-readable error identification
8.4 Preset System Architecture
The preset system is the primary configuration composition mechanism. It operates as a pipeline:
Framework Preset → Builder Preset → Addon Presets → User Config
How Presets Work
// Preset loading (code/core/src/common/presets.ts)
// 1. Resolve preset module path
// 2. Import the module
// 3. Extract exported functions
// 4. Merge with apply() mechanism
// Example preset export
export function webpack(config: WebpackConfig, options: Options): WebpackConfig {
// Modify and return webpack config
return { ...config, /* modifications */ };
}
export function viteFinal(config: ViteConfig, options: Options): ViteConfig {
// Modify and return vite config
return { ...config, /* modifications */ };
}
// Preset application
const finalConfig = await presets.apply('webpack', baseConfig, options);
// Calls each preset's webpack() in order, passing result forward
Preset Registration Points
| Hook | Purpose | Builder |
|---|---|---|
webpack |
Modify Webpack configuration | Webpack 5 |
webpackFinal |
Final Webpack config modification | Webpack 5 |
viteFinal |
Modify Vite configuration | Vite |
babel |
Modify Babel configuration | Both |
babelDefault |
Default Babel configuration | Both |
entries |
Add Preview entry points | Both |
managerEntries |
Add Manager entry points | Both |
previewAnnotations |
Add Preview annotations (decorators, etc.) | Both |
managerHead |
Add HTML to Manager <head> |
Both |
previewHead |
Add HTML to Preview <head> |
Both |
previewBody |
Add HTML to Preview <body> |
Both |
env |
Add environment variables | Both |
staticDirs |
Register static file directories | Both |
Framework Preset Pattern
Each framework package exports a preset that wires builder + renderer + framework-specific configs:
// Example: @storybook/react-vite/preset
export const viteFinal = async (config, options) => {
return {
...config,
plugins: [
...config.plugins,
react(), // @vitejs/plugin-react
docgenPlugin(), // React docgen
],
resolve: {
alias: {
// Framework-specific aliases
},
},
};
};
export const core = {
builder: '@storybook/builder-vite',
renderer: '@storybook/react',
};
8.5 Story Index System
The StoryIndexGenerator (code/core/src/core-server/utils/StoryIndexGenerator.ts) is the central indexing engine:
class StoryIndexGenerator {
// Initialize: scan files, parse CSF, build index
async initialize(): Promise<void>;
// Get the full index with statistics
async getIndexAndStats(): Promise<{ storyIndex: StoryIndex; stats: IndexStats }>;
// Clear the file matching cache (for testing/HMR)
static clearFindMatchingFilesCache(): void;
// Handle file changes for incremental re-indexing
async invalidate(path: string): Promise<void>;
}
Index format (v5):
{
"v": 5,
"entries": {
"components-button--primary": {
"type": "story",
"subtype": "story",
"id": "components-button--primary",
"title": "Components/Button",
"name": "Primary",
"importPath": "./src/components/Button.stories.tsx",
"exportName": "Primary",
"tags": ["dev", "test", "manifest"],
"componentPath": "./src/components/Button.tsx"
}
}
}
Indexing errors:
IndexingError— Wraps per-file indexing failures with import path contextMultipleIndexingError— Aggregates multipleIndexingErrorinstances- Duplicate story IDs throw:
Duplicate stories with id: ${firstEntry.id}
8.6 UniversalStore
The UniversalStore (code/core/src/shared/universal-store/) provides cross-frame state synchronization:
- Leader/Follower model — One leader (usually the Manager), multiple followers (Preview, addons)
- Timeout handling — Follower connection timeout triggers
UncaughtManagerError(tracked issue #34566) - Type-safe — Generic type parameter for store shape
- Event-driven — State changes propagate via the Channel system
Specialized stores built on UniversalStore:
StatusStore— Tracks per-story status (test results, a11y results)TestProviderStore— Manages test provider state (Vitest integration)ChecklistStore— Onboarding checklist progress
8.7 Testing Strategy
Unit and Integration Tests (Vitest)
# Run all tests
yarn test
# Run with watch mode
yarn test:watch
# Run specific project
yarn vitest run --project storybook-ui
# Run with coverage
yarn vitest run --coverage
The root vitest.config.ts configures:
NODE_OPTIONS=--max_old_space_size=4096for large test suites- Project-based configuration for different test targets
End-to-End Tests (Playwright)
# E2E tests run against built sandboxes
cd code/e2e-tests
npx playwright test
Configuration in code/playwright.config.ts:
- Uses
STORYBOOK_URLenv var for target URL STORYBOOK_TEMPLATE_NAMEfor template-specific tests- JUnit output via
PLAYWRIGHT_JUNIT_OUTPUT_NAME - Tests cover addon functionality, story rendering, MCP integration
Sandbox Testing
The sandbox system creates real Storybook projects for integration testing:
# Generate a sandbox
yarn task --task dev --template react-vite/default-ts --start-from=install
# Available templates (from code/sandbox/):
# angular-cli-default-ts, react-vite-default-ts, nextjs-default-ts,
# vue3-vite-default-ts, svelte-vite-default-ts, html-vite-default-ts, etc.
8.8 Code Patterns
Component Story Format (CSF) 4.0
// Modern CSF with factory pattern
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
backgroundColor: { control: 'color' },
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
};
export const WithPlayFunction: Story = {
args: { label: 'Click me' },
play: async ({ canvasElement, mount }) => {
await mount();
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole('button'));
},
};
definePreviewAddon Pattern
Used by all addons in Storybook 10:
import { definePreviewAddon } from 'storybook/internal/csf';
import * as addonAnnotations from './preview';
import type { MyAddonTypes } from './types';
export default () => definePreviewAddon<MyAddonTypes>(addonAnnotations);
renderToCanvas Pattern
Each renderer implements this function:
// React renderer (simplified)
export async function renderToCanvas(
{ storyFn, showMain, showError, forceRemount }: RenderContext,
canvasElement: HTMLElement
) {
const Story = storyFn();
const root = createRoot(canvasElement);
root.render(<Story />);
showMain();
}
8.9 storybook init — Service Architecture
The create-storybook package (code/lib/create-storybook/) uses a command/service pattern for project initialization:
Commands (executed in sequence):
PreflightCheckCommand— Validates environment, checks for existing StorybookProjectDetectionCommand— Detects project type (React, Vue, Angular, etc.)FrameworkDetectionCommand— Maps project type to Storybook frameworkUserPreferencesCommand— Prompts for preferences (language, addon selection)GeneratorExecutionCommand— Runs framework-specific generatorAddonConfigurationCommand— Configures selected addonsDependencyInstallationCommand— Installs npm dependenciesFinalizationCommand— Final setup, telemetry, success message
Services:
AddonService— Addon discovery and configurationFrameworkDetectionService— Maps renderer+builder combinations to framework packagesProjectTypeService— Detects project type from package.json and file structureTelemetryService— Reports init telemetryVersionService— Resolves compatible package versionsFeatureCompatibilityService— Checks feature support per framework
Generators (per framework):
code/lib/create-storybook/src/generators/
├── ANGULAR/ # Angular project generator
├── EMBER/ # Ember project generator
├── HTML/ # HTML project generator
├── NEXTJS/ # Next.js project generator
├── NUXT/ # Nuxt project generator
├── PREACT/ # Preact project generator
├── QWIK/ # Qwik project generator
├── REACT/ # React project generator
├── REACT_NATIVE/ # React Native generator
├── REACT_NATIVE_AND_RNW/ # React Native + Web generator
├── REACT_NATIVE_WEB/ # React Native Web generator
├── REACT_SCRIPTS/ # Create React App generator
├── SERVER/ # Server renderer generator
├── SOLID/ # Solid.js generator
├── SVELTE/ # Svelte project generator
├── SVELTEKIT/ # SvelteKit project generator
├── VUE3/ # Vue 3 project generator
└── WEB-COMPONENTS/ # Web Components generator
8.10 Contributing
The CONTRIBUTING/ directory contains the contributor documentation. Key points:
Development Setup
# Clone the repository
git clone https://github.com/storybookjs/storybook.git
cd storybook
# Install dependencies (Yarn 4.10.3, managed via corepack)
corepack enable
yarn install
# Build all packages
yarn build
# Start development Storybook
yarn start # Alias for: yarn task --task dev --template react-vite/default-ts
# Run the internal Storybook UI
cd code && yarn storybook:ui
Build System
The monorepo uses a custom task runner (scripts/tasks/) orchestrated by Nx:
| Task | Purpose |
|---|---|
yarn build |
Build a single package |
yarn check |
Type-check a package |
yarn lint |
Run ESLint |
yarn test |
Run Vitest |
yarn task --task dev |
Start a development sandbox |
yarn task --task build |
Build a sandbox |
Code Quality
- Formatting:
oxfmt(Rust-based formatter, viayarn fmt:check/yarn fmt:write) - Linting: ESLint 8 with custom local rules (
scripts/eslint-plugin-local-rules/) - Dead code: Knip (
yarn knip) - Type checking: TypeScript strict mode
- Pre-commit: Husky + lint-staged
Package Publishing
All packages publish from the code/ workspace with "access": "public" in publishConfig. Versions are managed monorepo-wide at 10.4.0-alpha.10. The @storybook/ npm scope is used for all public packages except the storybook core package and create-storybook.
9. Integration Points
9.1 Vitest Addon Integration
The Vitest addon (@storybook/addon-vitest) enables running Storybook stories as Vitest tests:
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Vitest | >= 3.0.0 | Required minimum |
| MSW | >= 2.0.0 | Only if MSW is installed |
| Builder | Vite only | Webpack not supported |
| Config format | Non-CJS | .cts/.cjs rejected |
| Workspace format | Non-JSON | JSON workspace files rejected |
Supported Frameworks
| Framework | Supported |
|---|---|
@storybook/react-vite |
Yes |
@storybook/nextjs-vite |
Yes |
@storybook/vue3-vite |
Yes |
@storybook/svelte-vite |
Yes |
@storybook/sveltekit |
Yes |
@storybook/html-vite |
Yes |
@storybook/preact-vite |
Yes |
@storybook/web-components-vite |
Yes |
@storybook/react-native-web-vite |
Yes |
@storybook/nextjs (Webpack) |
No |
@storybook/angular |
No |
@storybook/ember |
No |
Configuration
// vitest.workspace.ts
import { defineWorkspace } from 'vitest/config';
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
export default defineWorkspace([
{
extends: 'vite.config.ts',
plugins: [storybookTest()],
test: {
name: 'storybook',
browser: {
enabled: true,
provider: 'playwright',
headless: true,
},
setupFiles: ['.storybook/vitest.setup.ts'],
},
},
]);
The AddonVitestService class (code/core/src/cli/AddonVitestService.ts) handles postinstall setup, checking prerequisites and generating config files. It can skip Playwright installation via STORYBOOK_CLI_SKIP_PLAYWRIGHT_INSTALLATION.
9.2 Chromatic Visual Testing
Chromatic integration is a first-class concern:
{
"dependencies": {
"@chromatic-com/storybook": "^5.1.2",
"chromatic": "^13.3.4"
}
}
Configuration via the @chromatic-com/storybook addon, which provides:
- Visual snapshot capture per story
- Interaction-aware snapshots (waits for play functions)
- TurboSnap support (only test changed stories)
9.3 CI System Integration
Storybook includes built-in CI detection and optimization:
// Detected via CI environment variable
if (process.env.CI) {
// Skip interactive prompts
// Disable animations
// Optimize output for log parsing
}
The --ci flag on CLI commands explicitly enables CI mode, which:
- Disables interactive prompts
- Uses non-interactive package install
- Suppresses browser auto-open
- Enables deterministic output
9.4 Framework-Specific Integration Notes
Next.js (@storybook/nextjs and @storybook/nextjs-vite)
The Next.js frameworks provide comprehensive module mocking:
| Module | Mock Path | Purpose |
|---|---|---|
next/router |
src/export-mocks/router/ |
App Router mocking |
next/navigation |
src/export-mocks/navigation/ |
Navigation hooks (useRouter, usePathname, etc.) |
next/link |
src/export-mocks/link/ |
Link component with router context |
next/image |
Via aliases | Image component (uses unoptimized fallback) |
next/headers |
src/export-mocks/headers/ |
cookies(), headers() mocking |
next/cache |
src/export-mocks/cache/ |
Cache function mocking |
@next/font |
src/font/ |
Google Fonts and local fonts |
Important
React Server Components (RSC) require React >= 18.3. The React renderer validates this at startup and throws: "React Server Components require React >= 18.3" if the requirement is not met.
The @storybook/nextjs framework (Webpack) handles Next.js version detection via __NEXT_VERSION and adapts its configuration accordingly. It includes Babel plugins for font optimization and SWC configuration for fast compilation.
The @storybook/nextjs-vite framework uses a dedicated Vite plugin (src/vite-plugin/) that handles module aliasing, Styled JSX support, and routing mocks through Vite's resolve system.
Warning
GoogleFontsDownloadErrorandGoogleFontsLoadingErrorare thrown when Google Fonts cannot be downloaded or loaded during the build. This typically happens in offline/air-gapped environments. Configure a font fallback or proxy Google Fonts through your network.
Angular (@storybook/angular)
Angular integration includes:
- Angular CLI Builder —
start-storybookandbuild-storybookbuilders insrc/builders/ - Workspace detection — Reads
angular.jsonfor project configuration, build targets, and styles - Component analysis —
PropertyExtractorclass parses Angular decorators (@Component,@Directive,@Pipe,@Injectable) - BootstrapQueue — Serializes Angular component bootstrap to prevent race conditions
- Compodoc — Integration for generating documentation from Angular decorators via
setCompodocJson()
Caution
The
mountplay function feature is not supported in Angular due to zone.js polyfill transpiling away async/await patterns. SeeMountMustBeDestructuredErrorfor details.
The framework throws MissingAngularJsonError if no angular.json is found, and AngularLegacyBuildOptionsError for deprecated build options.
SvelteKit (@storybook/sveltekit)
SvelteKit integration provides mocks for SvelteKit-specific modules:
src/mocks/app/
├── environment.ts # $app/environment mock
├── navigation.ts # $app/navigation mock (goto, invalidate, etc.)
└── stores.ts # $app/stores mock (page, navigating, updated)
Note
Using
@storybook/svelte-vitein a SvelteKit project throwsSvelteViteWithSvelteKitError. You must use@storybook/sveltekitinstead, which includes the necessary SvelteKit module mocks.
The SvelteKit framework also includes Vite plugins (src/plugins/) for handling SvelteKit-specific build requirements.
Ember (@storybook/ember)
Ember integration relies on:
- Ember CLI build pipeline
package.jsondetection for Ember projects- Custom renderer that renders into
ember-output/
The framework throws Could not find package.json in: ${cwd} if the Ember project root cannot be located.
9.5 ESLint Plugin
The @storybook/eslint-plugin (code/lib/eslint-plugin/) provides:
// Flat config (ESLint 9+)
import storybook from '@storybook/eslint-plugin';
export default [
storybook.configs.recommended,
// or storybook.configs.strict
];
// Legacy config (ESLint 8)
module.exports = {
extends: ['plugin:storybook/recommended'],
};
Rules are located in code/lib/eslint-plugin/src/rules/. The StorybookRuleTester class extends ESLint's RuleTester for testing custom rules.
Note
The ESLint plugin supports both flat config (ESLint 9+) and legacy config formats. Flat configs are exported from
src/configs/flat/. If an unsupported config extension is detected, the system throwsUnsupported ESLint config extension: .${ext}.
9.6 Portable Stories
Storybook stories can be rendered outside of Storybook using the "portable stories" pattern:
// In a Vitest/Jest test
import { composeStories } from '@storybook/react';
import * as stories from './Button.stories';
const { Primary, Secondary } = composeStories(stories);
test('renders primary button', () => {
render(<Primary />);
expect(screen.getByRole('button')).toBeInTheDocument();
});
The test-storybooks directory includes portable stories kitchen-sink projects for:
- React (Vitest 3 + Playwright)
- Vue 3 (Cypress + Playwright)
- Svelte (Cypress + Playwright)
- Next.js
9.7 MCP (Model Context Protocol) Integration
Storybook 10 includes MCP server integration for AI tools, tested in code/e2e-tests/addon-mcp.spec.ts:
- Serves SSE (Server-Sent Events) endpoint for tool communication
- Enables AI assistants to interact with running Storybook instances
- Uses
STORYBOOK_TYPEandSTORYBOOK_SANDBOX_DIRenv vars for configuration