Mastering Chromatic’s trace utility
🎬 Debugging TurboSnap with the Chromatic Trace Utility
Modern applications have complex import relationships. A simple utility function might be used by dozens of components, and a change to that function could potentially affect many stories. When using TurboSnap, you might notice that changing one component triggers snapshots for multiple unrelated stories. This happens when changes propagate through your dependency graph in unexpected ways.
Chromatic’s trace utility helps you visualize these connections and optimize your project structure by mapping these relationships so you can understand the impact of your changes. Let’s review an example of how you can use the utility to see the impact of changing a component, such as a button:
npx chromatic trace ./src/stories/Atoms/Button.jsx
By default, the CLI will output trimmed results:
ℹ Traced 1 changed file to 5 affected story files:
— src/stories/Atoms/Button.js [changed]
∟ src/stories/Atoms/Button.stories.js
∟ [story index]
— src/stories/Atoms/Button.js [changed]
∟ src/stories/Atoms/Button.stories.js
∟ src/stories/Atoms/Composed.stories.js
∟ [story index]
— src/stories/Atoms/Button.js [changed]
∟ src/stories/Pages/SecondPage.jsx
∟ src/stories/Pages/SecondPage.stories.js
∟ [story index]
— src/stories/Atoms/Button.js [changed]
∟ src/stories/Components/UserProfile.js
∟ src/stories/Components/UserProfile.stories.js
∟ [story index]
— src/stories/Atoms/Button.js [changed]
∟ src/stories/Components/ProfileSummary.jsx
∟ src/stories/Components/ProfileSummary.stories.jsx
∟ [story index]
This output gives us insight into the blast radius of the file, letting you determine which stories are affected by changes to this file.
For comparison, you can run the same command for an imported CSS file and see if there’s any difference:
npx chromatic trace ./src/stories/Atoms/Button.css
Perhaps you’ll find that the Button styles have a direct impact on a component that doesn’t use the Button but reuses some of the Button’s styles. Reusing styles isn’t recommended because it creates hidden dependencies. Changing a Button’s padding could unexpectedly break a card component that happened to import those same styles. The trace utility exposes these architectural anti-patterns, showing you exactly how styling changes ripple through your application.
Using the trace utility
1. Configure your Storybook to generate stats JSON
Ensure that you’re generating a stats JSON file during your Storybook build. You can do this by adding the --stats-json flag to your build script in package.json:
# Build with preview-stats.json
npm run build-storybook -- --stats-json
# Optional: create a trimmed version
npx chromatic trim-stats-file
The preview-stats.json file contains your complete dependency graph, while the trimmed version removes noise like node_modules dependencies for clearer analysis. The trace utility requires a stats file in order to map dependencies.
2. Trace one or more files to see affected stories
Trace a single file by passing the file path:
npx chromatic trace ./src/utils/dateFormatter.js
Pass multiple file paths to trace multiple files at once:
npx chromatic trace ./src/components/Button.js ./src/hooks/useButton.js
# Files with different extensions
npx chromatic trace ./src/utils/helpers.js ./src/utils/constants.ts ./src/styles/main.css
3. Adjust verbosity of the output using the --mode/-m flag
Use expanded to see underlying modules:
npx chromatic trace -m expanded src/components/Button/Button.jsx
Results:
— src/components/Button/Button.js [changed]
∟ src/components/Button/Button.stories.js
∟ [story index]
∟ src/components/Header/Header.js
∟ src/components/Header/Header.stories.js
∟ [story index]
Using compact will show only the list of dependent story files, omitting their connections:
# See only affected story files
npx chromatic trace -m compact src/components/Button/Button.jsx
Results:
ℹ Traced 1 changed file to 3 affected story files:
src/components/Button/Button.stories.js
src/components/Header/Header.stories.js
src/components/App/App.stories.js
Use globbing features
Basic globbing is supported when using the trace utility. You can use a * character to trace an entire directory:
# ✅ WORKS
npx chromatic trace src/components/Button/*
npx chromatic trace src/components/*
# ❌ WON'T WORK
npx chromatic trace src/components/Button/
npx chromatic trace src/components/
Use basic characters (*, **, [], ?) to simplify your file path:
npx chromatic trace **/[abc]tomic/*/Accordion.ts?
# trace output match
Traced files...
[ 'src/components/atomic/accordion/Accordion.tsx' ]
Additional configuration options
Custom stats file location
By default, the trace utility expects your stats file to be in the storybook-static directory as either preview-stats.json or preview-stats.trimmed.json. If you’re using a custom build directory, your stats file is output to a different directory than your build directory.
You can also use the -s/--stats-file flag to specify the custom stats file name:
# Use a custom stats file name
npx chromatic trace -s storybook-static/custom-stats.json src/components/Button/Button.jsx
# Stats file in different directory
npx chromatic trace -s build-artifacts/preview-stats.json src/components/Modal/Modal.jsx
# With multiple files
npx chromatic trace -s my-stats.json src/components/Button/Button.jsx src/components/Modal/Modal.jsx
Specify base directory in a monorepo
If you’re running the trace utility in a monorepo with multiple Storybook projects or your project is nested, you can pass the -b/--base-dir option to specify the package directory:
# Storybook nested in packages/storybook directory
npx chromatic trace -b packages/storybook src/components/Button/Button.jsx
# Multiple packages structure
npx chromatic trace -b apps/web src/components/Button/Button.jsx
Test impact of ignoring specific files
You can test the impact of ignoring specific files using the -u/--untraced option:
# Ignore a specific utility file
npx chromatic trace src/components/Button/Button.jsx -u src/utils/helpers.js
# Ignore a CSS file
npx chromatic trace src/components/Button/Button.jsx -u src/styles/shared.css
# Multiple specific files
npx chromatic trace src/components/Button/Button.jsx -u src/utils/helpers.js -u src/styles/theme.css
Examples
Barrel files
Let’s say you’re using a similar component structure that relies on barrel (or index) files:
src/
components/
index.js # exports * from './Button', './Modal', etc.
Button/
Modal/
You observe that changing one component affects many unrelated stories. For example, you identify that changing the Button affects Modal stories. Use the trace utility to test whether the barrel file is responsible for overly-scoping:
# Confirm that Button changes affect Modal
npx chromatic trace ./src/components/Button/Button.jsx
# Test if the barrel file is the culprit using --untraced
npx chromatic trace ./src/components/Button/Button.jsx --untraced=./src/components/index.js
If the second command shows fewer affected stories, you’ve identified the barrel file as the culprit. Barrel files commonly increase the blast radius of your changes since they may introduce unrelated files to a component’s dependency graph. The solution is to skip the barrel file and use direct imports:
# Replace
import { Button } from './components'
# with
import Button from './components/Button/Button'
Direct imports ensure the dependency graph can follow the file without tracing unrelated modules. This is essential for global configurations (such as your .storybook/preview file) and barrel files with wide imports.
Shared utility dependencies
Let’s say you’d like to trace a currency utility:
# You updated a formatting function
npx chromatic trace ./src/utils/formatCurrency.js
A change to this utility function affects multiple components unexpectedly. The output shows it affects:
- ProductPrice.jsx
- CartSummary.jsx
- InvoiceTable.jsx
- AdminDashboard.jsx (unexpected!)
It’s necessary to review how the currency utility is being imported by the Admin Dashboard component and other components being imported into Admin Dashboard. If you discover a third file cascading the changes to AdminDashboard.jsx, you can try testing the impact of ignoring it:
# Trace without the third file to see if they're truly needed
npx chromatic trace ./src/utils/formatCurrency.js --untraced=./src/components/ThirdFile.jsx
This helps you distinguish between direct dependencies (components that actually use the utility) and transitive dependencies (components that import other components that use the utility).
Confirm changes with Git
Utilize these Git commands along with trace to confirm which files have changed and their impact, based on your dependency graph:
# Trace only files changed in the most recent commit
npx chromatic trace $(git diff --name-only HEAD~1 HEAD)
# Trace files changed between two specific branches
npx chromatic trace $(git diff --name-only develop main)
# Trace uncommitted changes
npx chromatic trace $(git diff --name-only)
Suggested fixes
Unused imports in dependency graph
Problem: Trace utility reveals dependencies that aren’t actually used.
Solution: Remove the unnecessary imports entirely.
Why: Projects accumulate unused imports over time, silently increasing bundle size and dependency complexity, making it difficult to understand how changes propagate.
Broad import patterns
Problem: Components import entire libraries or barrel files (ex. import * from 'src/components').
Solution: Replace with specific, targeted imports (ex. import { Button } from 'src/components/Button').
Why: Broad imports create hidden dependencies — changing one part of a library can unexpectedly affect many unrelated components.
Monolithic utility files
Problem: Large files combine multiple responsibilities.
Solution: Split into focused, single-responsibility modules.
Why: This allows components to import only what they actually need, reducing the impact radius of changes and making dependencies explicit.
False positive dependencies
Problem: Trace shows dependencies that shouldn’t logically exist.
Solution: Tweak project configuration and advance options.
Why: Misconfigured optimization settings (like sideEffects) prevent accurate dependency analysis. Another thing that can cause issues with the analysis is the use of wildcard exports in barrel files, as they make tree-shaking more challenging. The trace won’t identify what specific option must be changed, but can help identify the issue.
Widespread but necessary dependencies
If dependencies are genuinely used across multiple components, document them to build institutional knowledge. This enables your team to evaluate potential ripple effects before making changes.
When dependencies are part of a shared library or design system and are tested separately (or can be isolated for better scoping), importing those components from the built package can be beneficial. This approach helps prevent unnecessary changes from being detected, as built packages are generally excluded from git. For more information, see importing those components from the built package.
Next: Use the trace utility to diagnose preview file rebuilds
When unexpected changes impact your preview file, this can lead to more rebuilds than expected. Learn how to pinpoint the root cause of your preview rebuilds using the trace utility.
Read next chapter