Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Storybook Administrator & Developer Guide

Generated May 2026 from storybookjs/storybook at 245043f

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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-vite to 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 via jiti for 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 optional titlePrefix fields

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-regexp and throws Error: Invalid glob if 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 framework field throws MissingFrameworkFieldError. An invalid framework name throws InvalidFrameworkNameError. If the framework module cannot be evaluated (e.g., missing dependency), CouldNotEvaluateFrameworkError is thrown.

3.2.4 staticDirs

Directories to serve as static files:

const config: StorybookConfig = {
  staticDirs: [
    '../public',
    { from: '../assets', to: '/static' },
  ],
};

Warning

Using both staticDirs in main config and the -s CLI flag simultaneously throws ConflictingStaticDirConfigError. 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 in title--name format
  • viewMode — story or docs
  • args — URL-encoded args override
  • globals — 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, UpgradeStorybookUnknownCurrentVersionError is thrown.

The upgrade process:

  1. Detects current Storybook version
  2. Checks for blockers (incompatible configurations) via the autoblock system
  3. Runs applicable automigrations from code/lib/cli-storybook/src/automigrate/fixes/
  4. Updates package versions
  5. 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 configuration
  • manager — Manager UI panels/toolbar items
  • preview — Preview decorators/parameters
  • postinstall — 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:

  1. Very large codebases with thousands of story files
  2. Complex glob patterns scanning too many directories
  3. 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 stories
  • vite-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
  • DependencyCollector plugin 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:

  1. Using specific glob patterns instead of overly broad ones
  2. Splitting stories into separate directories with targeted specifiers
  3. Using titlePrefix to avoid ID collisions
  4. Enabling build.test.disableAutoDocs in 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 Origin header correctly. Stripping or rewriting the Origin header 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 localhost with dynamically generated ports

For strict CSP environments:

  1. Allow frame-src 'self' for the Preview iframe
  2. Allow connect-src 'self' ws: for WebSocket connections
  3. Consider unsafe-inline for styles if using CSS-in-JS in stories
  4. 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 init or storybook add, the CLI downloads packages from npm. In air-gapped environments, configure your npm registry to use an internal mirror. The CLI throws Failed 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:

  1. PostMessage (channels/postmessage/) — Manager-to-Preview communication via window.postMessage
  2. 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 context
  • MultipleIndexingError — Aggregates multiple IndexingError instances
  • 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=4096 for 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_URL env var for target URL
  • STORYBOOK_TEMPLATE_NAME for 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):

  1. PreflightCheckCommand — Validates environment, checks for existing Storybook
  2. ProjectDetectionCommand — Detects project type (React, Vue, Angular, etc.)
  3. FrameworkDetectionCommand — Maps project type to Storybook framework
  4. UserPreferencesCommand — Prompts for preferences (language, addon selection)
  5. GeneratorExecutionCommand — Runs framework-specific generator
  6. AddonConfigurationCommand — Configures selected addons
  7. DependencyInstallationCommand — Installs npm dependencies
  8. FinalizationCommand — Final setup, telemetry, success message

Services:

  • AddonService — Addon discovery and configuration
  • FrameworkDetectionService — Maps renderer+builder combinations to framework packages
  • ProjectTypeService — Detects project type from package.json and file structure
  • TelemetryService — Reports init telemetry
  • VersionService — Resolves compatible package versions
  • FeatureCompatibilityService — 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, via yarn 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

GoogleFontsDownloadError and GoogleFontsLoadingError are 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-storybook and build-storybook builders in src/builders/
  • Workspace detection — Reads angular.json for project configuration, build targets, and styles
  • Component analysis — PropertyExtractor class 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 mount play function feature is not supported in Angular due to zone.js polyfill transpiling away async/await patterns. See MountMustBeDestructuredError for 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-vite in a SvelteKit project throws SvelteViteWithSvelteKitError. You must use @storybook/sveltekit instead, 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.json detection 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 throws Unsupported 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_TYPE and STORYBOOK_SANDBOX_DIR env vars for configuration