Upgrades hurt most when they are rare
The stores that dread upgrades are the ones that treat them as rare, large events. Two years of skipped patches turn into a single high-risk project, and the project keeps getting postponed because it is scary.
Treating upgrade and patch work as a continuous practice inverts that. Small, frequent updates are low-risk and routine, and the store never drifts far enough behind to make the next step frightening.
This article covers the kinds of updates Magento ships, the tools that tell you what will break, the readiness checklist before any upgrade, and the cadence that keeps a store current instead of stranded.
The kinds of updates, and why they differ
Not every update is the same size or the same risk. Treating them all as "an upgrade" is why they get batched into one dreaded event.
- Security patches, shipped as patch levels like 2.4.7-p3, which fix disclosed vulnerabilities and should be applied quickly.
- Quality patches, targeted fixes for specific bugs, applied individually rather than as a full version bump.
- Minor version upgrades, such as 2.4.6 to 2.4.7, which change supported dependencies and can include backward-incompatible changes.
- Dependency updates, for PHP, the database, and the search engine, which have to stay inside the supported matrix.
Each kind has its own risk profile and its own cadence. Security patches are urgent and usually small; minor upgrades are larger and planned.
Security patches come first, and quickly
A disclosed vulnerability is public knowledge, and attackers scan for the exact versions that are behind on it. Security patches are the one category that should not wait for a convenient window.
Applying a security patch is usually a small, contained change compared to a version upgrade. The cost of staying current on security is low, and the cost of falling behind is the entire point of an attacker's automated scan.
The Quality Patches Tool
Adobe ships targeted fixes through the Quality Patches Tool, installed with composer require magento/quality-patches. It lets you apply specific fixes without waiting for the next full release.
The commands are straightforward. ./vendor/bin/magento-patches status shows what is available and applied, and ./vendor/bin/magento-patches apply with a patch ID applies an individual fix.
This matters for readiness because it decouples bug fixes from version upgrades. A specific issue can be resolved now, on your current version, rather than forcing a larger upgrade to get one fix.
Know what will break before you upgrade
The expensive surprises in an upgrade are the backward-incompatible changes and the extensions that do not support the target version. Both can be checked in advance.
The Upgrade Compatibility Tool scans your codebase against a target version and reports the incompatibilities it finds. Running vendor/bin/uct upgrade:check against the version you plan to move to surfaces the code that will need attention before you commit to the upgrade.
Alongside it, composer audit flags dependencies with known vulnerabilities, and checking each extension's version constraints against the target release tells you which ones block the move. Together these turn an upgrade from a leap of faith into a scoped piece of work.
A readiness pipeline turns an upgrade into a sequence of checks rather than a single risky event.
The readiness checklist before any upgrade
Before touching production, a short list separates a safe upgrade from a risky one. None of it is exotic, and skipping any of it is where upgrades go wrong:
- A verified backup of the database and code, tested to actually restore.
- A staging environment that matches production in code, config, and data, so the test means something.
- An extension compatibility check against the target version, with a plan for each incompatible one.
- A rollback plan, including how to revert code and restore the database inside the maintenance window.
- A test plan covering the critical paths: add to cart, checkout, payment, search, and admin order processing.
The staging-parity item is the one most often faked. A staging environment that has drifted from production tests a store you do not actually run.
Extensions are the usual blocker
In practice, the thing that holds up most upgrades is not Magento itself. It is the third-party extensions that have not shipped a version compatible with the target release.
Each extension declares supported versions in its composer.json, and a single package with a narrow constraint can block the whole upgrade from resolving. The readiness question for each one is simple: is there a compatible release, and if not, do you replace it, isolate it, or remove the feature.
Answering that per extension, ahead of time, is what prevents the upgrade from stalling halfway. An extension gap discovered mid-upgrade, with the store already changed, is the worst time to learn a vendor never shipped support.
Backups you have actually restored
Every upgrade plan names a backup. Far fewer confirm the backup actually restores, which is the only property that matters when you need it.
The backup covers the database, the code, and the media, and the restore should be practiced on a non-production environment. A team that has restored its backup once knows how long it takes and that it works, which turns rollback from a gamble into a known quantity.
Staging parity is the check that gets faked
A staging test only predicts production when staging matches production. This is the readiness item most often claimed and least often true.
Real parity means the same code, the same configuration, and representative data, not a staging environment that drifted months ago. Configuration should come from config.php and version control so it applies identically, and the data should be recent enough that the upgrade exercises real volume.
When staging has drifted, the upgrade "passed" on a store you do not run, and the surprises move to production. Confirming parity before the test is what makes the test worth anything.
Testing the critical paths
An upgrade can compile cleanly and still break checkout. Verification has to cover behavior, not just whether the commands succeeded.
The critical paths are the ones that make money or run the business: add to cart, checkout, payment, search, and admin order processing. Automated tests through Magento's functional testing framework cover these repeatably, and even a manual walk of each one catches regressions that infrastructure checks miss.
Prioritize by impact. A cosmetic glitch on a category page is a ticket; a checkout that fails for one payment method is a reason to hold the release.
Readiness is a short list of confirmable facts, not a feeling that the upgrade will probably be fine.
Run it on staging, then verify on production
The upgrade itself follows a fixed sequence: update through Composer, run setup:upgrade, compile with setup:di:compile, and deploy static content. Doing this on staging first is what catches the problems while they are cheap.
After the production upgrade, verification is its own step. Confirm the deploy mode, that indexers are valid, that cron is running, and that no new errors are flooding the logs, then walk the critical paths by hand.
An upgrade is not done when the commands succeed. It is done when the store is verified healthy, which is a different and more important test.
Rollback is part of the plan, not the panic
Every upgrade needs a way back. The database backup, the previous code release, and maintenance mode are the three pieces, and they have to be ready before you start, not assembled during an incident.
A rollback plan you have thought through turns a failed upgrade into an inconvenience. A rollback you improvise at 2am, with a database that changed during the failed attempt, turns it into an outage.
This is why the tested backup matters more than any single check. It is the difference between a bad upgrade and a bad day.
Maintenance windows and the hours after
Upgrades belong in a planned window, timed for low traffic and communicated to the team beforehand. A store put into maintenance mode during a quiet hour loses far less than one that breaks during peak.
The work does not end when the store comes back up. The first hours after an upgrade are when traffic exercises code paths that testing did not, so watching the error rate and the order rate closely during that window catches regressions while they are still small.
A quiet plan for those first hours, with someone watching the logs and the order flow, turns a risky moment into a monitored one. That is the difference between finding a regression yourself and hearing about it from a customer.
The pre-flight dependency check
Before committing to an upgrade, Composer can dry-run the resolution and tell you whether the target version is even installable. This is a read-only check that changes nothing.
Commands like composer prohibits name the packages that conflict with a target version, and setup:upgrade --dry-run reports what an upgrade would do without applying it. Together they let you see the full shape of the upgrade before a single file changes.
Running these first turns the upgrade from a leap into a preview. You learn what breaks, what blocks, and what the database change will be, all while the store is still safely on its current version.
Vendor and community patches
Beyond Adobe's own patches, you will sometimes apply a fix as a raw patch file, from a vendor or from a community source. These are managed differently and deserve their own discipline.
The common approach is the composer-patches package, which applies named patch files during install so the fix is recorded in composer.json and reapplied on every deploy. That is far safer than editing files by hand, because a hand-applied patch is invisible to the next Composer update and gets silently overwritten.
The rule is that every patch, from any source, must live in version control and reapply automatically. A fix that only exists on one server is drift waiting to happen, not a patch.
Composer is how you apply it
Modern Magento upgrades run through Composer, not a downloaded archive. You require the target version, let Composer resolve the dependency tree, and commit the updated lock file.
The lock file is the point. It records the exact versions of every package, so the same set installs identically on staging and production, which is what makes the staging test meaningful.
When Composer cannot resolve the target version, it is telling you about a conflict, usually an extension constraint, before anything changed. That refusal is a feature: it is the blocker surfacing at the cheapest possible moment.
What setup:upgrade actually does
After the Composer step, setup:upgrade is what brings the database in line with the new code. It applies declarative schema changes and runs the data patches each module ships.
This is the step that can leave a half-applied schema if it fails partway, which is why the tested backup matters and why verifying setup:db:status afterward is part of the process. An upgrade is not complete until the database state matches the code.
Following it, setup:di:compile and static content deployment rebuild the compiled code and assets for the new version. Skipping either leaves the store running mismatched or slow, even though the version bump technically succeeded.
Keep a written runbook
The steps of an upgrade are the same every time, which means they belong in a runbook rather than in someone's memory. A written sequence removes the improvisation that causes mistakes under pressure.
The runbook lists the pre-upgrade checks, the exact commands in order, the verification steps, and the rollback procedure. It is the difference between an upgrade anyone on the team can run and one that only works when a specific person is available.
It also improves with each upgrade. Every surprise becomes a new line in the runbook, so the next upgrade is a little smoother than the last, which is the whole point of a continuous practice.
Measuring readiness as a number
Readiness is easier to act on when it is concrete rather than a feeling. A few measures turn it into something you can track over time.
How many versions behind is the store, how many extensions block the next version, how many security patches are unapplied, and when was the backup last restored successfully. Each is a number, and together they describe exactly how ready the store is to move.
Tracking those numbers turns upgrade readiness into a metric rather than an argument. A store trending toward more versions behind and more unapplied patches is drifting into the expensive big-bang upgrade, and the numbers say so before the pain does.
Cadence is what makes it continuous
The practice that keeps a store healthy is a schedule, not heroics. Security patches applied promptly, quality patches as needed, and minor upgrades on a planned cadence keep the gap between your version and the current one small.
A store that never falls more than one version behind has short, low-risk upgrades. A store that skips upgrades for years faces a long chain of backward-incompatible changes all at once, which is the project everyone dreads.
The math is simple. Frequent small upgrades cost less in total than rare large ones, and they carry far less risk per step.
Readiness is a state you maintain
Upgrade readiness is not a task you complete once. It is a condition you keep the store in: current on security, close to the latest version, with staging that matches production and a rollback plan that works.
Readiness is also cumulative. The runbook, the tested backup, and the staging parity you build for one upgrade all carry forward, so each cycle is cheaper than the last rather than starting from scratch.
Knowing exactly how far behind you are, what would break in the next step, and whether you could roll back is the difference between a store that upgrades smoothly and one that is stuck. Establishing that readiness, with evidence, is one of the most valuable outcomes a structured platform review delivers.