Migrating from Chromatic
This guide walks through migrating an existing Chromatic project to StoryShelf. It assumes you have a Chromatic project with existing baselines and CI integration.
Coming from Lost Pixel? See the Lost Pixel migration guide.
Prerequisites
Section titled “Prerequisites”- A running StoryShelf server (see Getting started)
- Admin access to your Chromatic project
- Ability to modify CI pipelines
- GitHub/GitLab admin for status check updates
1. Export baselines from Chromatic (manual — no API)
Section titled “1. Export baselines from Chromatic (manual — no API)”Chromatic does not provide a public API to export baselines. You cannot programmatically migrate baseline images.
Workaround: On first StoryShelf run, all snapshots will appear as “new” or “changed” (against default branch). Your team will need to re-accept them once. This is a one-time cost.
Tip: If you have a small number of critical baselines, you can download them from the Chromatic UI and package them as a baseline archive to import. This isn’t practical for large projects.
StoryShelf doesn’t repeat this lock-in: once you’re on it, baseline export/import moves your baselines to any other instance or into backups.
2. Deploy StoryShelf server
Section titled “2. Deploy StoryShelf server”Follow Getting started to deploy:
- Choose database (SQLite for single-node, Turso/Postgres for serverless)
- Choose storage (local for single-node, S3-compatible for multi-node)
- Choose auth (OIDC recommended for teams)
- Configure Git provider (GitHub/GitLab) for status checks
3. Create project with matching settings
Section titled “3. Create project with matching settings”In StoryShelf UI or via CLI:
storyshelf create --url https://shelf.example.com --name "My Design System" --token $ADMIN_TOKENMatch Chromatic settings where applicable:
- Project name → same as Chromatic
- Default branch → same as Chromatic (usually
main) - Pixel threshold → match Chromatic’s threshold if customized
- Viewports → configure in server
ShelfConfig.viewportsto match Chromatic
4. Update CI pipeline
Section titled “4. Update CI pipeline”Chromatic CI (before):
Section titled “Chromatic CI (before):”- name: Chromatic uses: chromatic-action@v1 with: projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} buildScriptName: build-storybookStoryShelf CI (after):
Section titled “StoryShelf CI (after):”- name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 # affected capture diffs against history
- name: Build Storybook run: npx build-storybook -o storybook-static
- name: Upload to StoryShelf run: npx storyshelf upload --token ${{ secrets.STORYSHELF_TOKEN }} --sha ${{ github.sha }} --branch ${{ github.ref_name }} env: STORYSHELF_URL: https://shelf.example.com STORYSHELF_SLUG: my-design-systemOr with .storybook/storyshelf.json committed:
- name: Upload to StoryShelf run: npx storyshelf env: STORYSHELF_TOKEN: ${{ secrets.STORYSHELF_TOKEN }}5. Parameter compatibility (dual-key)
Section titled “5. Parameter compatibility (dual-key)”StoryShelf reads both chromatic: and storyshelf: parameter keys. storyshelf: wins on conflict.
| Chromatic parameter | StoryShelf equivalent | Notes |
|---|---|---|
disableSnapshot | disableSnapshot | Works unchanged |
flakyTest | flakyTest | Works unchanged |
delay | delay | Works unchanged |
diffThreshold | diffThreshold | Works unchanged |
pauseAnimationAtEnd | pauseAnimationAtEnd | Works unchanged |
viewports | Server config | Set in ShelfConfig.viewports |
modes / globals | Not supported | Gap — no equivalent |
No code changes needed for existing chromatic: parameters. They work as-is.
6. Baseline model differences
Section titled “6. Baseline model differences”| Chromatic | StoryShelf |
|---|---|
| Global baseline + branch baselines | Per-branch baselines with default-branch fallback |
| Branch baselines independent | Feature branch accepts → branch baseline; merge to main → promotes to default |
| No GC (manual cleanup) | Auto GC: branchTtlDays (default 30), purgeTtlDays (default 30) |
Implication: On first run, feature branches will diff against main baseline. After accepting changes, they get their own branch baseline. Merging to main updates the default baseline automatically.
7. What you lose (honest gaps)
Section titled “7. What you lose (honest gaps)”| Feature | Chromatic | StoryShelf | Impact |
|---|---|---|---|
| TurboSnap | Yes (dependency graph) | Yes — affected capture (on by default) | Similar skip rates on Vite Storybooks; needs fetch-depth: 0 and preview-stats.json |
| Cross-browser | Chrome, FF, Safari, Edge (branded, cloud) | Chromium / Firefox / WebKit, one per build | Set in project Settings → General or via API; baselines tracked per browser; no branded Safari/Edge |
| Modes/Globals | Yes | No | Theme/locale matrices need workarounds |
| A11y testing | Yes (aXe) | axe-core checks, on by default (runA11y) | Results are shown in review, not a review gate |
| Cloud parallelization | Automatic | Manual (testing.concurrency) | Limited by your server CPU/memory |
| Baseline export | UI only | API + UI | Cannot bulk-import Chromatic baselines |
| Flake detection | Auto-detect | Explicit flakyTest | Manual marking required |
8. What you gain
Section titled “8. What you gain”- Zero per-snapshot cost — Unlimited snapshots forever
- Full data ownership — Your DB, your storage, your network
- No vendor lock-in — MIT license, standard REST API, open source
- Flexible SSO — Any OIDC provider (Keycloak, Okta, Entra ID, etc.)
- Deploy anywhere — Node, Bun, Deno, Fly.io, Vercel, Cloudflare, Lambda, etc.
- Per-branch baselines with fallback — Cleaner for long-lived feature branches
- Persistent builds — Tag releases → never purged
9. Rollback plan
Section titled “9. Rollback plan”Keep Chromatic running in parallel for 1-2 sprints:
- Run both — Add StoryShelf upload as additional CI step (don’t remove Chromatic yet)
- Compare results — Verify StoryShelf catches same regressions
- Team training — Familiarize reviewers with StoryShelf UI
- Cutover — Remove Chromatic step, update GitHub status check requirements
- Archive — Export any critical Chromatic data before canceling subscription
10. Team onboarding checklist
Section titled “10. Team onboarding checklist”- ☐ Reviewers know how to approve/reject in StoryShelf UI
- ☐ GitHub status check renamed from
chromatictostoryshelf/testing(or your channel prefix) - ☐ Branch protection rules updated to require StoryShelf status
- ☐ CI secrets rotated (
CHROMATIC_PROJECT_TOKEN→STORYSHELF_TOKEN) - ☐ Documentation updated with StoryShelf workflow
- ☐ Chromatic subscription canceled (after verification period)
Q: Can I import Chromatic baselines? A: No public API. Baselines must be re-accepted on first StoryShelf run.
Q: Does StoryShelf support TurboSnap?
A: Yes, as affected capture — enabled by default with the same shape (ancestor → git diff → graph trace → selective render). Differences: Vite stats only, no per-snapshot billing (skipping saves CPU, not money), and unknown cases fail open to full renders. Replace --only-changed with nothing (it’s the default); use --full to opt out.
Q: Can I test Safari/Firefox?
A: Yes — set the project’s browsers list (for example ["chromium", "firefox", "webkit"], up to 3) via PATCH /api/v1/projects/:slug, or the single capture browser in Settings → General. Every build captures each listed engine in turn, with one baseline per engine; a newly added engine is seeded from its first build, auto-accepting stories whose primary-browser snapshot is clean.
Q: What about Modes/Globals? A: Not supported. Workaround: duplicate stories with different args, or use separate Storybook configs.
Q: How do I handle flaky tests?
A: Add parameters: { storyshelf: { flakyTest: true } } or tag flaky-test on the story. Build status stays green with warning.
Q: Can I run both during migration? A: Yes. Add StoryShelf as additional CI step. Compare results before cutover.