Baseline screenshots for a visual regression suite are binary files that change whenever the UI is intentionally redesigned. How would you decide between committing them to the application's git repository and keeping them in an external baseline store, and what does each cost?
answer
- binaries never delta-compress
- atomic with the commit, or not
- who approves, and how many teams
- storing less beats storing elsewhere
basics
~20 sCommitting baselines pins each image to the commit that changed it and needs no extra service, but grows repository history with binaries that ordinary review tools render poorly. An external store keeps the repository small and provides an approval interface, at the cost of a dependency and weaker version pinning.
solid answer
~50 sDecide from three numbers: how many screenshots you keep, how often they legitimately churn, and how many teams must approve changes. In-repo baselines are the simplest correct default — an image is versioned with the code that produced it, a branch carries its own expectations, and there is no external system to be down or to pay for; the costs are permanent history growth, pull requests whose diffs a reviewer cannot read without a tool that renders images, and unmergeable conflicts when two branches touch the same file. An external or hosted baseline store inverts that: the repository stays small, approval gets a purpose-built review interface, and baselines can be keyed per branch and promoted on merge — but you have added a dependency to your build, and the expected appearance is no longer guaranteed to travel with a checkout of an old commit. Small suites stay in-repo; large multi-team suites usually outgrow it.
go deeper
Know that baselines are image files that live somewhere versioned, and that the common starting point is simply committing them next to the tests.
Explain why binary files grow repository history permanently, why two branches editing the same baseline cannot be merged, and what a separate store changes about both.
Weigh the operational costs honestly on both sides — clone time and unreadable diffs versus a build-time dependency and a cost model — and say what would trigger a move.
Own it as a governance decision: whatever the storage, approvals must be attributable and branch expectations distinct, and reducing how many baselines exist is usually the higher-leverage move than relocating them.
## What is actually being stored A baseline is a lossless image, typically tens to hundreds of kilobytes, and there is one per screenshot per environment combination you check. Multiply: a hundred components, two viewports and two colour schemes is four hundred images, and every intentional redesign rewrites a slice of them. Because images are binary, a rewritten baseline is stored as a whole new object, not a delta — history grows monotonically. ## The case for keeping baselines in the repository - **Atomicity.** The expected appearance is versioned with the code that produces it. Checking out any commit gives you the images that commit expected, which makes bisecting a visual regression possible at all. - **Branching for free.** A feature branch carries its own updated baselines; merging brings both the code and the new expectations. No separate keying scheme is required. - **No dependency.** The suite runs offline, in any environment, with no service to authenticate against, be rate-limited by, or pay for. For a small team this is decisive. - **Ordinary review.** Approval is code review — the same mechanism, the same permissions, the same audit trail. The costs are real. Repository size grows forever, and it grows fastest exactly when the design system is most active. Cloning slows for everyone, including CI. Review UIs vary in how well they show image changes, and a reviewer with no side-by-side view is effectively approving blind. Concurrent updates to the same image cannot be merged, so one branch's intended change is silently discarded on the second merge. Git LFS mitigates the size problem by keeping pointers in history and blobs in a store, but it is itself an external dependency plus a bandwidth bill, so it is a middle position rather than a free win. ## The case for an external baseline store - **The repository stays a code repository.** History size becomes independent of how much visual churn the design system has. - **Purpose-built review.** A hosted diffing service shows baseline, actual and overlay side by side, tracks who approved what, and can group forty diffs caused by one shared-component change into a single decision. - **Branch semantics you choose.** Baselines can be keyed per branch, inherited from the branch point, and promoted to the main baseline on merge — which handles the concurrent-update problem the file-in-git model cannot. - **Cross-run history.** You can ask when a component last changed appearance, which a repository can also answer but far less conveniently. The costs: a build-time dependency whose outage blocks or degrades your pipeline, a per-snapshot cost model that quietly disciplines how many screenshots you take, an approval trail living outside your version control, and the loss of the guarantee that an old checkout carries its own expectations. There is also lock-in — baselines and approval history are not portable between services. ## How I would decide Start in-repo. It is the simplest thing that is correct, and most suites never outgrow it. Watch three signals, and move when two of them fire: 1. **Volume.** Baseline objects are a meaningful and growing share of repository size, or clone time has become a complaint. 2. **Coordination.** More than one team approves changes to overlapping screenshots, and binary conflicts are recurring rather than rare. 3. **Review quality.** Reviewers are approving image changes without looking, because the tooling makes looking expensive. And note the option that is often better than either: **take fewer, smaller screenshots.** A great deal of baseline volume comes from full-page captures at many combinations, where a targeted component capture would catch the same defects. Reducing what you store is cheaper than changing where you store it, and it improves triage at the same time. ## The non-negotiables either way Whichever model you pick, the same invariants must hold: a baseline is only replaced after a human has seen the diff; approvals are attributable; a branch's expectations are distinguishable from the main branch's; and the store is not a place where an approval can happen invisibly. Storage is a logistics decision layered on top of that governance, not a replacement for it.
- Where does Git LFS sit between the two options?It is a middle position: pointers stay in history so baselines remain versioned with the code and branch normally, while the blobs live in a separate store, keeping clones small. The price is that you have taken on an external dependency and a bandwidth cost anyway, and contributors need LFS configured, so it buys size relief without buying the review interface or the branch-promotion semantics.
- What breaks about bisecting a visual regression when baselines live outside the repository?Checking out an old commit no longer gives you the appearance that commit expected, because the store holds current baselines keyed by branch rather than by revision. You can usually still find historical images through the service, but the coupling is by convention rather than guaranteed by the checkout, so a bisect becomes a manual correlation exercise instead of a mechanical one.
- How does the storage decision interact with how many screenshots the suite takes?Directly, and it is the lever people reach for last. Per-snapshot pricing in a hosted service and history growth in a repository both scale with volume, so the same discipline helps either way: prefer targeted component captures over full-page ones, and justify each additional environment combination. Reducing the number of baselines is usually cheaper and improves triage more than relocating them.
saying these in an interview costs you the question
- Images compress away in git history, so size is fine
- Binary baseline conflicts can be merged like text
- A hosted service removes the need for human approval
- Always start with a paid visual testing service
- Storage choice has nothing to do with screenshot count