A regression is a software defect in which behavior that worked correctly in an earlier version breaks or degrades after a change, such as a code modification, an update, a configuration change or a new dependency. In software quality, the term marks a specific kind of failure: the product has moved backward, and something users already relied on no longer works as before.
Regressions matter because they erode trust faster than ordinary bugs. Users accept that new features may be imperfect, but they rarely tolerate losing something that used to work. For this reason, software teams treat regressions as high priority and invest in regression testing, the practice of re-running checks on existing functionality whenever the software changes.
How regressions arise
A regression appears when a change has unintended effects outside its intended scope. Software components depend on each other through shared code, data formats, timing and configuration, so modifying one part can alter assumptions that another part silently relied on.
Common triggers include refactoring that subtly changes behavior, a dependency upgrade with a modified interface, a performance optimization that breaks an edge case, an operating-system update that changes a system API, and a fix for one bug that reintroduces an older one. The last case is sometimes called a reopened or recurring defect.
Regressions are not limited to crashes or wrong results. Slower response times, higher memory use, worse battery life, broken accessibility and changed visual layout all count when they represent a measurable step backward from a previous release.
Types of regression
Teams classify regressions by what has degraded, because each type requires different detection methods. The following table summarizes the main categories.
| Type | What degrades | Typical detection |
|---|---|---|
| Functional regression | A feature gives wrong results or fails | Automated unit and integration tests |
| Performance regression | Speed, memory or resource use | Benchmarks with tolerance thresholds |
| Visual regression | Layout, rendering or styling | Screenshot comparison |
| Compatibility regression | Old files, devices or integrations | Test suites with legacy data |
| Security regression | A previously fixed vulnerability returns | Security test cases for past issues |
| Usability regression | Workflow becomes harder or slower | User feedback and usability testing |
Performance regressions are especially difficult, because a slowdown of a few percent per release may go unnoticed until it accumulates into a clearly sluggish product. Reliable detection requires stable test hardware and repeated measurements to separate real changes from noise.
Regression compared with related quality concepts
Regression is closely tied to other concepts in software quality, and precise distinctions help in prioritizing and reporting problems.
| Concept | Relationship to regression | Key difference |
|---|---|---|
| Regression | The defect itself | Something that worked now fails |
| New defect | Also a bug | Feature never worked correctly |
| Regression testing | Method to catch regressions | An activity, not a defect |
| Bug report | Document describing the failure | Should state last known good version |
| Crash report | Automatic evidence of failure | May reveal a regression after release |
| Technical debt | Common underlying cause | Fragile code makes regressions likely |
A good bug report for a regression names the last version that worked and the first version that fails. That pair of versions narrows the search dramatically, because the cause must lie among the changes made between them. Telemetry that tracks error rates per version serves the same purpose at scale.
Detecting and isolating regressions
Effective teams combine automated prevention, early detection and fast isolation. The table matches common techniques to the stage at which they act.
| Stage | Technique | Benefit |
|---|---|---|
| Before merge | Automated test suite in continuous integration | Blocks most functional regressions |
| Before release | Benchmarks and screenshot tests | Catches performance and visual changes |
| During rollout | Staged or canary releases | Limits the number of affected users |
| After release | Telemetry and crash reporting | Reveals failures missed by tests |
| Investigation | Bisection between versions | Finds the exact change at fault |
| Prevention | Test added for every fixed regression | Stops the same defect returning |
Bisection is the classic isolation method. Given one good and one bad version, the team tests the version halfway between them and repeats the process on the half that contains the fault. With version control tools such as git bisect, a range of 1,000 commits can be narrowed to one in about ten steps, because each step halves the search space.
Common pitfalls
Regression handling fails more often through process gaps than through missing tools. The following mistakes are typical in teams of every size.
- Fixing without a test: a regression repaired without an automated check tends to return during later changes.
- Flaky tests: tests that fail randomly teach developers to ignore failures, hiding real regressions.
- Testing only the change: narrow testing misses effects in distant parts of the system.
- Comparing performance on noisy machines: shared or variable hardware produces false alarms and hides real slowdowns.
- Reverting too slowly: when a release causes a serious regression, rolling back first and diagnosing later usually limits damage.
A useful habit is to track regressions as a separate category in the defect database. A rising share of regressions among new defects is an early signal that test coverage, code structure or release discipline is not keeping pace with the rate of change.
The idea in brief
A regression is when an update breaks something that used to work. You install a new version of an app, and a button that worked yesterday now does nothing. Nothing new was promised there. The software simply took a step backward.
Developers guard against this by re-checking old features after every change. It is like a mechanic who fixes the brakes and then also tests the lights and the horn. A repair in one place can disturb another.
A practical scenario
A team maintaining an accounting application releases version 5.3 with a faster report engine. Within two days, support receives several reports that invoices exported to PDF now show totals rounded to whole units instead of two decimal places. Version 5.2 handled this correctly, so the team classifies it as a functional regression with high priority.
The team first pauses the staged rollout so that only about ten percent of customers receive 5.3. Developers then run a bisection across the 240 commits between the two versions, which takes eight test runs and identifies a change that replaced a decimal type with a floating-point type for speed. They restore the decimal type, add an automated test with representative invoice amounts, and publish version 5.3.1. The outcome is a contained incident and a permanent safeguard against the same defect returning.