# How to Use Project Annotations in Storybook: setProjectAnnotations and setDefaultProjectAnnotations Explained

> Master Storybook project annotations. Learn how setProjectAnnotations and setDefaultProjectAnnotations ensure consistent UI rendering and global decorators for your components.

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

---

**Call `setProjectAnnotations` once in your test setup file to register global decorators and parameters from your `.storybook/preview` configuration, while framework packages automatically register their defaults via `setDefaultProjectAnnotations` to ensure rendering logic is always available.**

Project annotations in Storybook represent the global configuration—decorators, parameters, and global types—that apply to every story in your project. When testing stories outside the Storybook UI using utilities like `composeStory`, you must manually wire these globals using the `setProjectAnnotations` API from the storybookjs/storybook repository.

## What Are Project Annotations in Storybook?

Project annotations are the global settings defined in your [`.storybook/preview.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/preview.ts) (or `.js`) file. They include:

- **Global decorators** that wrap every story (e.g., theming providers, accessibility checkers)
- **Global parameters** for addon configuration (e.g., viewport settings, backgrounds)
- **Global types** for toolbar controls that persist across stories
- **Initial globals** for default state values

When running stories inside the Storybook UI, these annotations are loaded automatically. However, when composing stories for unit testing with `composeStory` or `composeStories`, you must explicitly register them using the portable stories API.

## setDefaultProjectAnnotations vs setProjectAnnotations: Key Differences

Storybook provides two distinct functions for registering project annotations, each serving a different purpose in the configuration hierarchy.

### setDefaultProjectAnnotations (Framework Defaults)

The `setDefaultProjectAnnotations` function stores baseline annotations that framework packages (like Vue, React, or Svelte) require to function. According to the source code in [`code/core/src/preview-api/modules/store/csf/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/core/src/preview-api/modules/store/csf/portable-stories.ts), this function assigns values to `globalThis.defaultProjectAnnotations`.

Framework wrappers call this internally to ensure their rendering logic—such as Vue’s `renderToCanvas` implementation—is always available before user configuration is applied. You typically do not call this function directly unless you are building a custom renderer.

### setProjectAnnotations (User Configuration)

The `setProjectAnnotations` function merges your project’s preview file configuration with the core and default annotations. As implemented in [`portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/portable-stories.ts), this function composes three layers:

1. **Core annotations** from `getCoreAnnotations()` (Storybook’s internal defaults)
2. **Default annotations** from `globalThis.defaultProjectAnnotations` (framework-specific baseline)
3. **User annotations** passed as the function argument

The merged result is stored in `globalThis.globalProjectAnnotations`, which `composeStory` and `composeStories` reference automatically when no explicit annotations are provided.

## How Project Annotations Are Merged Internally

Understanding the merge strategy helps debug configuration issues. The internal implementation in [`code/core/src/preview-api/modules/store/csf/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/core/src/preview-api/modules/store/csf/portable-stories.ts) uses `composeConfigs` to layer configurations:

```typescript
globalThis.globalProjectAnnotations = composeConfigs([
  ...getCoreAnnotations(),                     // Storybook’s internal defaults
  globalThis.defaultProjectAnnotations ?? {},   // Framework defaults (Vue, React, etc.)
  composeConfigs(annotations.map(extractAnnotation)), // User-provided preview config
]);

```

When `composeStory` executes, it normalizes the final configuration by merging the global project annotations with any story-specific overrides:

```typescript
const normalizedProjectAnnotations = normalizeProjectAnnotations(
  composeConfigs([
    defaultConfig ?? globalThis.globalProjectAnnotations ?? {}, // Global fallback
    projectAnnotations ?? {}, // Explicit override for this composition
  ])
);

```

This hierarchy ensures that framework essentials are never overwritten accidentally, while user configurations take precedence for global settings.

## Practical Implementation Examples

### Setting Up Project Annotations for Vue 3

Framework packages like `@storybook/vue3` automatically register their defaults before your configuration. In your test setup file:

```typescript
// .storybook/vitest.setup.ts
import { setProjectAnnotations } from '@storybook/vue3';
import * as projectAnnotations from './preview'; // Your .storybook/preview.ts

setProjectAnnotations(projectAnnotations);

```

The Vue wrapper in [`code/renderers/vue3/src/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/renderers/vue3/src/portable-stories.ts) internally calls `setDefaultProjectAnnotations` with Vue-specific rendering logic before executing your `setProjectAnnotations` call.

### Configuring React Project Annotations

The pattern is identical for React. The setup file registers your preview configuration:

```typescript
// vitest.setup.ts
import { setProjectAnnotations } from '@storybook/react';
import * as projectAnnotations from './.storybook/preview';

setProjectAnnotations(projectAnnotations);

```

React’s wrapper in [`code/renderers/react/src/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/renderers/react/src/portable-stories.ts) handles the framework defaults automatically.

### Using composeStory with Global Annotations

Once `setProjectAnnotations` is called in your setup file, individual tests require no additional configuration:

```typescript
import { render } from '@testing-library/vue';
import { composeStory } from '@storybook/vue3';
import Meta, { Primary as PrimaryStory } from './Button.stories';

const Primary = composeStory(PrimaryStory, Meta); // Automatically uses global annotations

test('renders primary button', async () => {
  const { getByText } = render(Primary, { props: { label: 'Hello world' } });
  expect(getByText(/Hello world/i)).not.toBeNull();
});

```

The `composeStory` function automatically references `globalThis.globalProjectAnnotations` when no explicit project annotations argument is provided.

### Overriding Annotations for Individual Tests

You can override global settings for specific test suites by passing annotations as the second argument to `composeStories`:

```typescript
import { composeStories } from '@storybook/react';
import * as stories from './Card.stories';

const customAnnotations = {
  decorators: [(Story) => <div className="test-wrapper"><Story/></div>],
};

const { Primary } = composeStories(stories, customAnnotations);
// customAnnotations are merged on top of global project annotations

```

This pattern is useful when you need test-specific wrappers that should not pollute the global configuration.

## Where Project Annotations Live in the Source Code

The implementation spans the core preview API and framework-specific wrappers:

- **[`code/core/src/preview-api/modules/store/csf/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/core/src/preview-api/modules/store/csf/portable-stories.ts)** – Contains the core `setDefaultProjectAnnotations` and `setProjectAnnotations` implementations, including the `composeConfigs` merge logic.
- **[`code/renderers/vue3/src/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/renderers/vue3/src/portable-stories.ts)** – Vue 3 wrapper that registers framework-specific defaults via `setDefaultProjectAnnotations` before re-exporting the core API.
- **[`code/renderers/react/src/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/renderers/react/src/portable-stories.ts)** – React wrapper following the same pattern for React-specific rendering logic.
- **[`test-storybooks/react/.storybook/vitest.setup.ts`](https://github.com/storybookjs/storybook/blob/main/test-storybooks/react/.storybook/vitest.setup.ts)** – Real-world example demonstrating the standard setup pattern in a test environment.

## Summary

- **Project annotations** are global configurations (decorators, parameters, globals) defined in `.storybook/preview` that must be registered when testing stories outside Storybook.
- **`setDefaultProjectAnnotations`** is used internally by framework packages (Vue, React, Svelte) to register renderer-specific essentials like `renderToCanvas`.
- **`setProjectAnnotations`** merges your preview file configuration with core and default annotations, storing the result in `globalThis.globalProjectAnnotations`.
- **Call `setProjectAnnotations` once** in a global test setup file (e.g., [`vitest.setup.ts`](https://github.com/storybookjs/storybook/blob/main/vitest.setup.ts)) to enable `composeStory` and `composeStories` to automatically apply your global configuration.
- **Override globally** by passing annotation objects directly to `composeStory` or `composeStories` when you need test-specific behavior.

## Frequently Asked Questions

### What is the difference between setProjectAnnotations and setDefaultProjectAnnotations?

`setDefaultProjectAnnotations` registers baseline annotations that framework packages require to function, such as Vue’s `renderToCanvas` implementation, and is called automatically by framework wrappers. `setProjectAnnotations` is the public API you call in your test setup to register your `.storybook/preview` configuration, which then merges with the defaults.

### Where should I call setProjectAnnotations in my test setup?

Call `setProjectAnnotations` once in a global setup file such as [`.storybook/vitest.setup.ts`](https://github.com/storybookjs/storybook/blob/main/.storybook/vitest.setup.ts), [`vitest.setup.ts`](https://github.com/storybookjs/storybook/blob/main/vitest.setup.ts), or [`jest.setup.js`](https://github.com/storybookjs/storybook/blob/main/jest.setup.js), importing your project annotations from `.storybook/preview`. This ensures that `composeStory` and `composeStories` automatically access your global decorators and parameters without requiring manual passing in every test file.

### Can I override global project annotations for a single story?

Yes, you can override global annotations for individual stories or test suites by passing a custom annotations object as the second argument to `composeStory` or `composeStories`. These overrides are merged on top of the global configuration stored in `globalThis.globalProjectAnnotations`, allowing test-specific wrappers or parameters without affecting the global state.

### How do framework-specific annotations get registered automatically?

Framework packages like `@storybook/vue3` and `@storybook/react` wrap the core `setProjectAnnotations` function and internally call `setDefaultProjectAnnotations` with their renderer-specific configuration before executing your call. This happens in files like [`code/renderers/vue3/src/portable-stories.ts`](https://github.com/storybookjs/storybook/blob/main/code/renderers/vue3/src/portable-stories.ts), ensuring essential rendering logic is present before your user-defined preview configuration is merged.