ScreenshotNeo

BlogHow-to

How to Use Chromatic with a Monorepo and Multiple Storybooks

Choose one shared Chromatic project or separate projects, then configure GitHub Actions, paths, tokens, and TurboSnap for multiple Storybooks.

By the ScreenshotNeo team4 October 20268 min read

To use Chromatic with a monorepo, choose one of two layouts: combine packages’ stories in a single Storybook and publish one Chromatic project, or keep Storybooks separate and run one Chromatic project per subproject. Choose a shared project when you want one catalog and status; choose separate projects when teams need independent project identities or pull request checks.

For separate projects in GitHub Actions, run Chromatic in each package’s working directory with that package’s project token. Confirm the build script and path bases before enabling TurboSnap. Chromatic’s monorepo guide, GitHub Actions guide, and TurboSnap setup guide document these patterns.

1. Choose one Chromatic project or several

Decision One combined Storybook and project Separate Storybooks and projects
Catalog One shared catalog containing stories from included packages Separate catalogs and configurations
Chromatic identity One project and publishing target One project for each subproject
CI setup One Chromatic invocation for the central Storybook One invocation and project token per subproject
Pull request checks One principal project status Separate build statuses can be used for each subproject
Ownership fit Useful when teams maintain a shared catalog Useful when subprojects need independent checks and configuration

Combine stories when the catalog is shared

Add each package’s story-file glob to the main Storybook’s stories configuration, then publish that Storybook to one Chromatic project. For example, in a root .storybook/main.ts:

import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: [
    '../packages/button/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
    '../packages/forms/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
    '../packages/navigation/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
  ],
  addons: [],
  framework: '@storybook/react-vite',
};

export default config;

Adjust the framework, addons, and globs to match your repository. A shared Storybook is simplest when its stories can use compatible configuration and dependencies. You can use TurboSnap or Chromatic’s onlyStoryFiles and onlyStoryNames controls to target snapshot testing. Avoid publishing an intentionally incomplete Storybook as the full catalog: stories absent from a published build are treated as removed.

Separate Storybooks when ownership or statuses differ

Create or link a Chromatic project for each Storybook. Store a distinct token for each project, and run Chromatic from the matching subproject directory. This means more configuration and CI invocations, in exchange for separate project identities and build statuses.

2. Configure GitHub Actions for multiple Storybooks

The following example runs two subprojects sequentially in one workflow. Replace the package paths, secret names, and package-manager commands for your repository. Use the current syntax and supported action version from Chromatic’s official GitHub Actions guide; action versions and runtime versions can change.

name: Chromatic

on:
  pull_request:
  push:
    branches: [main]

jobs:
  chromatic:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - run: npm ci

      - name: Publish web Storybook
        uses: chromaui/action@latest
        with:
          projectToken: ${{ secrets.CHROMATIC_WEB_TOKEN }}
          workingDir: packages/web

      - name: Publish admin Storybook
        uses: chromaui/action@latest
        with:
          projectToken: ${{ secrets.CHROMATIC_ADMIN_TOKEN }}
          workingDir: packages/admin

This is a template, not a timeless recommendation for action or Node versions. Check the current official workflow guidance before copying version pins into production. Checking out full Git history follows Chromatic’s documented workflow example and gives CI the repository history its comparisons need.

Build script and prebuilt output

Each working directory must provide the expected Storybook build script, commonly build-storybook. If the package uses another script name, configure buildScriptName as described in the action documentation. If a preceding CI step already generated static output, use storybookBuildDir to pass its directory. That path is relative to the current working directory.

- name: Publish web Storybook
  uses: chromaui/action@latest
  with:
    projectToken: ${{ secrets.CHROMATIC_WEB_TOKEN }}
    workingDir: packages/web
    buildScriptName: build-storybook
    # If output was built earlier in this package, for example:
    # storybookBuildDir: storybook-static

Parallel publishing

Chromatic’s GitHub Actions guidance recommends separate workflow files when running each subproject in parallel. This lets each workflow own its package directory and project token. If you keep the jobs sequential in one file, as above, each action step runs after the previous step. Choose the structure that matches how you want CI to schedule and report the projects.

3. Understand working directories and path bases

Monorepo configuration often fails because path options do not all resolve from the same directory. Chromatic documents these bases:

Option Path base
untraced, externals, storybookBaseDir Repository root
storybookConfigDir, storybookBuildDir Current working directory

workingDir changes the current working directory for the second group. It does not change the repository-root base for the first group. See Chromatic’s configuration reference and TurboSnap setup guide when setting these values.

For example, with workingDir: packages/web, set storybookBuildDir: storybook-static to refer to packages/web/storybook-static. A repository-root pattern in externals still needs a root-relative path such as ./packages/web/public/**. Do not add the package prefix mechanically to every option.

If you invoke the CLI from the repository root rather than using a package working directory, Chromatic’s TurboSnap guide shows configuring storybookBaseDir and storybookConfigDir to point at the package and its .storybook directory. Confirm each option’s documented path base first.

4. Add TurboSnap after the default workflow is reliable

TurboSnap uses changed files and dependency tracing to limit which stories are snapshotted. It still builds and publishes Storybook; it is not a way to skip the build. Establish normal, reliable builds first, then enable it and verify that the change graph covers the files that affect your UI.

The current setup guide lists prerequisites including Chromatic CLI 10.0 or later, Storybook 6.5 or later or Vitest 4 or later, Git 2.28.0 or later, supported Webpack/Vite-based setup, ten successful CI builds, and UI Tests enabled. These requirements can change, so check the live setup guide when implementing.

Monorepo dependencies and external files

Cross-package dependencies affect which stories should be considered changed. Make package relationships explicit in the dependency graph. Chromatic’s Nx guidance discusses implicitDependencies for expressing relationships relevant to TurboSnap. If stories rely on static assets or other files outside the standard import graph, check whether they need to be declared with externals.

For a combined Storybook, TurboSnap can select affected stories across the shared catalog. For deliberate targeting, use onlyStoryFiles or onlyStoryNames rather than publishing a Storybook that omits stories from the catalog.

5. Troubleshoot common monorepo failures

Symptom Likely cause Fix
The wrong Storybook builds The action has the wrong workingDir, or the token belongs to another project Check each step’s package directory and project-specific secret together.
Chromatic cannot find the build script The subproject does not expose the expected script name Add the script, set buildScriptName, or supply prebuilt output with storybookBuildDir.
Config path appears to repeat the package path A current-working-directory path was written as if it were repository-root-relative With workingDir: packages/web, use .storybook, not packages/web/.storybook, for a cwd-relative config directory.
TurboSnap includes unexpected packages or rebuilds broadly Base directory, dependency relationships, or root-relative externals/untraced patterns are inaccurate Review path bases, package dependencies, and external files against the configuration reference.
A project’s pull request check is missing after linking or renaming The Git provider may still have the old required check name Remove and re-add the required check using its current name.
A partial publish marks stories removed The published build omitted stories that belong to the full catalog Publish the complete Storybook and use snapshot filters for targeted testing.
Upload exceeds Chromatic’s documented file limit The project has more than 5,000 uploaded files, including stories and assets Chromatic documents zip: true for projects exceeding that upload limit; consult the current action guide.

6. Performance, reliability, and cost considerations

  • Build time: TurboSnap limits snapshot testing; it does not remove the Storybook build and publish. Keep the build path correct before optimizing snapshots.
  • Change detection: Incomplete dependency or external-file declarations can make change selection unreliable. Include cross-package relationships and relevant static assets in the setup.
  • CI scheduling: Sequential steps are straightforward but run one after another. Separate workflow files are Chromatic’s documented approach for parallel subproject publishing.
  • Upload size: Chromatic currently documents a 5,000-file upload limit and recommends its zip option above that threshold. Verify the current limit and setting when maintaining the workflow.
  • Cost: The reviewed documentation does not establish pricing or plan limits for this setup. Check Chromatic’s current pricing separately rather than assuming that combining projects changes cost.

7. A practical rollout checklist

  1. Decide whether the team needs one shared catalog/status or independent subproject statuses.
  2. For a combined catalog, include each package’s story globs in the principal Storybook.
  3. For separate projects, create/link each project and store one matching token per subproject.
  4. Set each action’s workingDir and confirm the package’s build script or prebuilt directory.
  5. Check path bases for config, build, base directory, external, and untraced options.
  6. Publish normal builds successfully before enabling TurboSnap.
  7. Verify dependency relationships and files outside the import graph, then test changed-file selection.
  8. Use complete Storybook publishes; use story filters when only selected stories should be snapshotted.

Or skip the browser setup

If your workflow also needs website screenshots, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for its options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo accepts cookie banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, and failed loads are never billed. Its MCP server gives AI agents tools to take screenshots, inspect page information, and capture PDFs. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Should every package have its own Chromatic project?

Only when separate project identities or independent pull request statuses are useful. A shared catalog can publish through one project.

Can I use one token for multiple Storybooks?

Chromatic’s documented separate-subproject pattern uses a project token for each subproject. Keep each action invocation paired with its project’s token.

Does TurboSnap avoid building Storybook?

No. It narrows snapshot testing through change detection and dependency tracing; the Storybook still builds and publishes.

Can separate Storybooks run at the same time?

Yes. Chromatic’s GitHub Actions guidance recommends separate workflow files for parallel runs.

Where should I check when a path looks wrong?

First identify whether the option resolves from repository root or the current working directory, then account for workingDir only where applicable.

Sources