# How to Migrate from Older Storybook Versions: Complete Guide to Storybook 8

> Migrate from older Storybook versions to Storybook 8 with our comprehensive guide. Learn about Node.js requirements, ESM config, API changes, and addon updates to ensure a smooth transition.

- Repository: [Storybook/storybook](https://github.com/storybookjs/storybook)
- Tags: migration-guide
- Published: 2026-02-27

---

**Storybook 8 requires Node.js 20.19 or 22.12, ESM-only configuration files, and the removal of the `storiesOf` API, alongside TypeScript module resolution changes and new addon package names.**

Migrating from Storybook 7 (or earlier) to Storybook 8 involves significant architectural changes that affect configuration, module resolution, and story authoring. This guide covers the essential steps to upgrade your [`.storybook/main.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/main.ts), TypeScript settings, and addon imports based on the official `storybookjs/storybook` repository's next branch.

## Upgrade Node.js to Version 20.19 or 22.12

Storybook 8 drops support for older Node runtimes. The minimum required version is **Node.js 20.19** or **22.12**.

Older Node versions cannot handle the new ESM `import-meta` resolution without experimental flags. Verify your version before proceeding:

```bash
node --version

```

## Convert Configuration Files to ESM

All files inside the `.storybook` directory—including [`main.ts`](https://github.com/storybookjs/storybook/blob/main/main.ts), [`preview.ts`](https://github.com/storybookjs/storybook/blob/main/preview.ts), and any custom preset files—must be valid **ES modules**. This means:

- No `require()` statements
- No `__dirname` or `__filename` without explicit construction
- All relative imports require explicit file extensions (`.js`, `.ts`)

If you still need CommonJS compatibility, import `createRequire` from `node:module`.

### Example: Converting [`.storybook/main.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/main.ts) to ESM

```typescript
// .storybook/main.ts
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

// Reconstruct __dirname for ESM compatibility
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export default {
  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    resolve(__dirname, '../my-addon/index.js'),  // Explicit extension required
    '@storybook/addon-essentials',
  ],
  core: {
    // Builder must be fully resolved absolute path
    builder: resolve(__dirname, '../node_modules/@storybook/builder-vite'),
  },
};

```

## Update TypeScript Module Resolution

Your [`tsconfig.json`](https://github.com/storybookjs/storybook/blob/main/tsconfig.json) must use a `moduleResolution` setting that supports the `types` condition. Storybook 8 removed all `typesVersions` fields, so the old `"node"` resolution can no longer locate typings.

Set `"moduleResolution"` to `"bundler"`, `"node16"`, or `"nodenext"`:

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

```

## Resolve Builder Paths Explicitly

If you configure `core.builder` in [`.storybook/main.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/main.ts), it must now be a **fully resolved absolute path**. Relative paths or package name strings are no longer valid.

```typescript
// ❌ Invalid
core: {
  builder: '@storybook/builder-vite',
}

// ✅ Valid
import { resolve } from 'node:path';
core: {
  builder: resolve(__dirname, '../node_modules/@storybook/builder-vite'),
  // Or using require.resolve if in a hybrid setup
  builder: require.resolve('@storybook/builder-vite'),
}

```

## Migrate Addon APIs and Imports

The old `@storybook/addons` package has been split into two distinct packages:

- **`@storybook/manager-api`** for manager UI configuration
- **`@storybook/preview-api`** for preview (canvas) functionality

Legacy shim packages—including `@storybook/channel-postmessage`, `@storybook/channel-websocket`, `@storybook/client-api`, `@storybook/store`, and `@storybook/api`—have been merged into these new APIs.

### Updating addons.setConfig

```typescript
// Before (Storybook 7)
import { addons } from '@storybook/addons';
addons.setConfig({ theme: myTheme });

// After (Storybook 8)
import { addons } from '@storybook/manager-api';
addons.setConfig({ theme: myTheme });

```

## Remove storiesOf and Adopt CSF

The `storiesOf` API has been **completely removed**. You must migrate all stories to **Component Story Format (CSF)**. For dynamic story generation, use the experimental `experimental_indexers` API.

### Migration Example

```typescript
// ❌ Removed API
import { storiesOf } from '@storybook/react';
storiesOf('Button', module)
  .add('Primary', () => <Button primary>Click me</Button>);

// ✅ CSF 3.0 (Recommended)
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Button',
  component: Button,
};
export default meta;

type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
    primary: true,
    children: 'Click me',
  },
};

```

## Update Testing Utilities

The `@storybook/testing-library` package is deprecated. All testing utilities have moved to **`@storybook/test`**.

```typescript
// Before
import { userEvent } from '@storybook/testing-library';

// After
import { userEvent } from '@storybook/test';

```

## Configure Vite Plugins Explicitly

Framework-specific Vite plugins are **no longer auto-added** by Storybook. You must import and configure them explicitly in your [`vite.config.ts`](https://github.com/storybookjs/storybook/blob/main/vite.config.ts).

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
});

```

If using [`.storybook/main.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/main.ts) with `viteFinal`, ensure you preserve existing plugins:

```typescript
// .storybook/main.ts
import react from '@vitejs/plugin-react';

export default {
  viteFinal: async (config) => ({
    ...config,
    plugins: [react(), ...(config.plugins ?? [])],
  }),
};

```

## Adjust Portable Stories for Testing

The `composeStory` and `composeStories` functions have changed behavior:

- **Project annotations** are now merged rather than overwritten
- The `play` function may return `undefined`
- **Vue 3**: Returns a component instance instead of a render function

### Vue 3 Portable Stories Example

```typescript
// Before (Returns function)
import { composeStory } from '@storybook/vue3';
const Primary = composeStory(stories.Primary, stories.default);
render(Primary({ foo: 'bar' })); // ❌

// After (Returns component)
import { render } from '@testing-library/vue';
const Primary = composeStory(stories.Primary, stories.default);
render(Primary, { props: { foo: 'bar' } }); // ✅

```

## UI and Runtime Changes

The Manager UI now runs on **React 18**, which affects any custom addon UI components. Default keyboard shortcuts have changed, and system tags (`docs`, `story`) have been removed from the UI.

Review any custom shortcut overrides or addon UI code for React 18 compatibility.

## Summary

- **Node.js 20.19+** is required for ESM support
- Convert [`.storybook/main.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/main.ts) and presets to **ESM** with explicit file extensions
- Update [`tsconfig.json`](https://github.com/storybookjs/storybook/blob/main/tsconfig.json) to use `"moduleResolution": "bundler"` (or `node16`/`nodenext`)
- Set `core.builder` to a **fully resolved absolute path**
- Replace `@storybook/addons` with `@storybook/manager-api` and `@storybook/preview-api`
- Remove all `storiesOf` usage in favor of **CSF 3.0**
- Switch from `@storybook/testing-library` to `@storybook/test`
- Add **explicit Vite plugins** in [`vite.config.ts`](https://github.com/storybookjs/storybook/blob/main/vite.config.ts)
- Handle `composeStory` returning components (not functions) in Vue 3

## Frequently Asked Questions

### What Node.js version is required for Storybook 8?

Storybook 8 requires **Node.js 20.19** or **22.12** minimum. Earlier versions lack native support for the ESM `import-meta` resolution features that Storybook 8 relies on for configuration loading.

### Do I have to convert my Storybook config to ESM?

Yes. Files in the `.storybook` directory—including [`main.ts`](https://github.com/storybookjs/storybook/blob/main/main.ts), [`preview.ts`](https://github.com/storybookjs/storybook/blob/main/preview.ts), and any custom presets—must be valid ES modules. You cannot use `require()` or implicit file extensions in relative imports. Use `import { createRequire } from 'node:module'` if you need to import CommonJS modules.

### What happened to the `storiesOf` API?

The `storiesOf` API has been **completely removed** in Storybook 8. You must rewrite any stories using this API to the **Component Story Format (CSF)**. For dynamic story generation scenarios, use the `experimental_indexers` API instead.

### Why am I getting TypeScript errors after upgrading?

Storybook 8 removed all `typesVersions` fields from its packages. Your [`tsconfig.json`](https://github.com/storybookjs/storybook/blob/main/tsconfig.json) must use `"moduleResolution": "bundler"`, `"node16"`, or `"nodenext"` to properly resolve type definitions. The legacy `"node"` resolution cannot locate the new typings.