workleap-chromatic-best-practices
Workleap Chromatic Best Practices
Guide for auditing and updating repositories to follow Workleap's Chromatic best practices.
Audit Workflow
When asked to audit or update a repository for Chromatic best practices, follow these steps in order:
Step 1: Locate Chromatic Configuration
Search for existing Chromatic setup:
chromatic.config.json
.storybook/preview.ts
.storybook/preview.tsx
.github/workflows/*chromatic*.yml
.github/workflows/*storybook*.yml
package.json (scripts section)
If no Chromatic configuration exists, ask the user if they want to set it up.
Step 2: Audit and Fix Each Practice
2.1 Check untraced Configuration (Optional)
Find: chromatic.config.json
Optional configuration:
{
"$schema": "https://www.chromatic.com/config-file.schema.json",
"untraced": ["**/package.json"]
}
Trade-off: Adding package.json to untraced reduces snapshot costs but may cause missed visual regressions when updating NPM packages that include breaking visual changes (e.g., UI library updates like Hopper).
When to use untraced:
- Projects where dependency updates rarely affect visuals
- Teams that manually verify visual changes after dependency updates
When to avoid untraced:
- Projects heavily dependent on UI libraries (Hopper, design systems)
- When visual regression detection for dependency updates is critical
Action: Ask the user about their preference. If they want to reduce costs and accept the trade-off, add the untraced option. Otherwise, skip this optimization.
2.2 Audit Storybook Preview Imports
Find: .storybook/preview.ts or .storybook/preview.tsx
Look for barrel file imports:
// BAD - barrel file import triggers full build when ANY export changes
import { ThemeProvider, I18nProvider } from "@app/providers";
import { something } from "../src";
import { util } from "@app/utils";
Replace with direct imports:
// GOOD - direct imports only trigger rebuilds for specific file changes
import { ThemeProvider } from "@app/providers/ThemeProvider";
import { I18nProvider } from "@app/providers/I18nProvider";
Detection patterns:
- Imports from paths ending in
/index(explicit or implicit) - Imports from package-level paths like
@app/utilsor../src - Multiple named imports from a single module (often indicates barrel)
Action: Refactor to direct imports. If the direct path doesn't exist, note it as a recommendation.
2.3 Check for Local Chromatic Usage
Find: package.json scripts section
Bad patterns:
{
"scripts": {
"chromatic": "chromatic",
"test:visual": "chromatic --project-token=...",
"storybook:test": "chromatic"
}
}
Action: Remove or comment out local Chromatic scripts. Chromatic should only run from CI via pull requests, never locally.
Why: Running Chromatic locally triggers the entire visual test suite, wasting snapshots.
2.4 Check CI Workflow for Label-Based Triggering
Find: GitHub Actions workflow files that run Chromatic
Required pattern:
on:
push:
branches:
- main
pull_request:
branches:
- main
types:
- opened
- labeled
workflow_dispatch:
jobs:
chromatic:
steps:
- name: Early exit if "run chromatic" label is not present
if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'run chromatic')
run: |
echo "No \"run chromatic\" label present. Skipping Chromatic workflow."
exit 78
Bad patterns:
# BAD - runs on every PR without label check
on:
pull_request:
jobs:
chromatic:
# No label check
Action: Add label-based conditional execution. The label name should be run chromatic.
2.5 Check CI Workflow for Required Flags
Find: Chromatic action step in CI workflow
Required flags:
- name: Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
onlyChanged: true # Enables TurboSnap
exitOnceUploaded: true # Faster CI, doesn't wait for build
autoAcceptChanges: main # Auto-accept on main branch
Check for:
onlyChanged: true- Required for TurboSnapexitOnceUploaded: true- Recommended for faster CIautoAcceptChanges: main- Recommended to auto-accept baseline on main
Action: Add missing flags to the Chromatic action.
2.6 Check CI Workflow for Proper Git Checkout
Find: Checkout step in CI workflow
Required configuration:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0 # Required for TurboSnap
ref: ${{ github.event.pull_request.head.ref }}
env:
CHROMATIC_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }}
CHROMATIC_SHA: ${{ github.event.pull_request.head.sha || github.ref }}
CHROMATIC_SLUG: ${{ github.repository }}
Critical check: fetch-depth: 0 is required for TurboSnap to work properly.
Action: Add fetch-depth: 0 and Chromatic environment variables if missing.
2.7 Check Browser Configuration
Find: Chromatic CLI flags in CI workflow or chromatic.config.json
Look for multi-browser flags:
# BAD - doubles/triples snapshot count
npx chromatic --browsers chrome,firefox
Required: Chrome only (default, no flag needed)
Action: Remove multi-browser flags unless explicitly required.
2.8 Check for Renovate/Changesets Exclusion
Find: CI workflow and branch ruleset configuration
Recommendation: Exclude Renovate bot and Changesets branches from the required status check ruleset, not from the workflow itself.
Action: Document recommendation to configure branch ruleset to exclude:
renovate/*brancheschangeset-release/*branches
2.9 Identify Large Files in Preview Dependencies
Scan files imported by .storybook/preview.ts[x] for problematic patterns:
Problematic file types:
- Localization files (
**/resources.json,**/translations/*.json) - Route definitions (large route config objects)
- Environment configs
- Utility files with many exports
Detection: Files with >20 exports or >500 lines that are imported by preview.
Action: Document findings and recommend splitting into smaller, focused modules.
2.10 Check for Workflow Optimizations
Find: CI workflow file
Recommended patterns:
# Concurrency to cancel in-progress runs
concurrency:
group: chromatic-${{ github.ref }}
cancel-in-progress: true
# Label removal after completion
- name: Remove "run chromatic" label after Chromatic completion
if: github.event_name == 'pull_request'
uses: actions/github-script@v8
with:
script: |
github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'run chromatic'
});
Action: Add concurrency settings and label removal step if missing.
Step 3: Generate Audit Report
After completing the audit, provide a summary:
## Chromatic Best Practices Audit
### Findings
| Practice | Status | Action Required |
|----------|--------|-----------------|
| `untraced` config (optional) | ✅/❌/N/A | [action or user declined] |
| Preview barrel imports | ✅/❌ | [action] |
| No local Chromatic scripts | ✅/❌ | [action] |
| CI label-based triggering | ✅/❌ | [action] |
| CI `onlyChanged: true` flag | ✅/❌ | [action] |
| CI `fetch-depth: 0` | ✅/❌ | [action] |
| CI Chromatic env vars | ✅/❌ | [action] |
| Chrome-only snapshots | ✅/❌ | [action] |
| CI concurrency settings | ✅/❌ | [action] |
| CI label auto-removal | ✅/❌ | [action] |
| Large file dependencies | ✅/❌ | [action] |
### Changes Made
- [list of files modified]
### Recommendations
- [list of suggested improvements that require user decision]
- Consider adding `untraced` for package.json (trade-off: may miss UI library regressions)
- Configure branch ruleset to exclude Renovate/Changesets branches
- Add `run chromatic` as a required status check
Reference: Why These Practices Matter
TurboSnap Preservation
TurboSnap analyzes Git changes to snapshot only affected stories. These patterns disable TurboSnap and trigger full builds (all stories):
| Change Type | Files |
|---|---|
| Storybook preview | .storybook/preview.ts[x] |
| Barrel file dependencies | Any index.ts[x] imported by preview |
| Package dependencies | **/package.json (optionally use untraced) |
| Large shared files | Routes, constants, localization |
| Shallow git clone | Missing fetch-depth: 0 |
Snapshot Cost Multipliers
| Configuration | Snapshots per Story |
|---|---|
| Chrome only | 1x |
| Chrome + Safari | 2x |
| Chrome + Safari + Firefox | 3x |
CI Trigger Strategy
Running Chromatic on every PR commit wastes snapshots on work-in-progress:
- Use
run chromaticlabel to trigger workflow - Auto-remove label after completion
- Make workflow a required status check to remind reviewers
Monorepo-Specific Audit
For Turborepo/monorepo projects, additional checks:
-
Per-package Chromatic configs: Each package with Storybook should have its own
chromatic.config.json -
Turborepo cache in CI: Workflow should restore/save Turborepo cache:
- name: Restore Turborepo cache uses: actions/cache/restore@v5 with: key: ${{ runner.os }}-turbo-chromatic-${{ github.sha }} restore-keys: | ${{ runner.os }}-turbo-chromatic- ${{ runner.os }}-turbo- path: .turbo -
Module-level triggering: For modular architecture, configure CI to run Chromatic only for affected modules
Critical Rules
- Never invent Chromatic options - Only use documented configuration
- CI-only execution - Never recommend running Chromatic locally
- Preserve TurboSnap - Every recommendation should maintain TurboSnap effectiveness
- Cost awareness - Every snapshot counts toward monthly budget