Planning an Upgrade
Choosing the Magento version you can actually reach, and finding the extensions and PHP requirements that set the timeline.
composer why-not magento/product-community-edition 2.4.9An upgrade in Magento is a Composer operation. The project's composer.json requires a metapackage: a package with no code of its own whose job is to pin every core module to one version. Magento Open Source uses magento/product-community-edition; Adobe Commerce uses magento/product-enterprise-edition. Changing that one constraint is the upgrade. Everything else is consequence.
Read before running anything
Start with the release notes for the target version and the backward-incompatible changes reference on developer.adobe.com. Requirements move between minor releases. Magento Open Source 2.4.9, released 12 May 2026, drops PHP 8.2 and 8.3 and runs on PHP 8.4 or 8.5, so the PHP version on the server is part of the plan rather than a detail. Confirm the search engine as well, with bin/magento config:show catalog/search/engine.
Which versions you can reach
Minor releases are 2.4.8 and 2.4.9. A version with a -p suffix, such as 2.4.9-p1, is a security patch release: security fixes only, no new features, so it is a much shorter project than a minor upgrade.
The extensions set the timeline
Ask Composer which installed package blocks the target: composer why-not magento/product-community-edition 2.4.9. Then run the Upgrade Compatibility Tool (UCT), a separate Adobe tool that scans your own modules for calls into core code the target version removed or deprecated. It installs from repo.magento.com as its own project and needs Composer keys for that repository.
Example
<?php
// app/code/Vendor/Upgrade/Console/Command/CurrentVersionCommand.php
declare(strict_types=1);
namespace Vendor\Upgrade\Console\Command;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CurrentVersionCommand extends Command
{
public function __construct(
private readonly ProductMetadataInterface $productMetadata,
?string $name = null
) {
parent::__construct($name);
}
protected function configure(): void
{
$this->setName('vendor:upgrade:current');
$this->setDescription('Print the installed product, version and edition.');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln(sprintf(
'%s %s (edition: %s)',
$this->productMetadata->getName(),
$this->productMetadata->getVersion(),
$this->productMetadata->getEdition()
));
return Cli::RETURN_SUCCESS;
}
}
// Register the class as an argument of Magento\Framework\Console\CommandList
// in app/code/Vendor/Upgrade/etc/di.xml, then run:
// bin/magento setup:di:compile && bin/magento cache:flush
//
// $ bin/magento vendor:upgrade:current
// Magento 2.4.9 (edition: Community)When to use it
- Deciding whether this quarter's work is 2.4.8, 2.4.9 or a security patch release.
- Telling a merchant which extensions must be replaced before the upgrade can start at all.
- Checking whether the server's PHP version blocks the target release.
- Estimating the upgrade from a count of UCT critical issues in your own modules.
More examples
Constructor promotion and the longhand it desugars to
Magento 2.4.9 runs on PHP 8.4, so both forms are legal and both are visible in the core. The promoted form declares the property, types it and assigns it in one place; the longhand does the same in three. Magento's dependency injection reads the constructor signature either way, so neither form changes how the object is built. Recognise both: older modules and older core classes use the longhand.
// Shorthand: promoted constructor property (PHP 8.0 and later).
class CurrentVersionCommand extends Command
{
public function __construct(
private readonly ProductMetadataInterface $productMetadata,
?string $name = null
) {
parent::__construct($name);
}
}
// Longhand: the same class, written out. Identical behaviour.
class CurrentVersionCommand extends Command
{
private ProductMetadataInterface $productMetadata;
public function __construct(
ProductMetadataInterface $productMetadata,
?string $name = null
) {
$this->productMetadata = $productMetadata;
parent::__construct($name);
}
}Finding the package that blocks the target version
Run this on a copy of production with the real composer.lock, not on a clean install. Each line names a package and the constraint that conflicts, which turns the upgrade into a list: upgrade the extension, replace it, or take over maintaining it. This is the step that produces a date, because a third-party extension with no 2.4.9 release is a procurement problem rather than a code problem.
# What is installed now
bin/magento --version
composer show magento/product-community-edition
# Which installed package refuses the target version.
# "composer prohibits" is the same command under its other name.
composer why-not magento/product-community-edition 2.4.9
composer prohibits magento/product-community-edition 2.4.9
# Everything that has a newer release, direct requirements only
composer outdated --direct
# Keep the answer: this file is the upgrade plan's evidence
composer why-not magento/product-community-edition 2.4.9 > var/upgrade-blockers.txtScanning your own modules with the Upgrade Compatibility Tool
UCT reads your installed modules and compares what they call against the target version's code. Issues come back at three levels: warning, error and critical. Critical means the class or method does not exist in the target version, so that code will fatal. Reach for this once the Composer blockers are cleared, because it tells you how much of the work is yours rather than an extension vendor's.
# UCT is a separate Composer project, installed outside the store,
# and it needs keys for repo.magento.com.
# Check the whole installation against the version you intend to reach
bin/uct upgrade:check /var/www/magento --coming-version=2.4.9
# Short option for the same thing
bin/uct upgrade:check /var/www/magento -c 2.4.9
# Hide what is already broken on the current version, and
# show only issues at error level or worse
bin/uct upgrade:check /var/www/magento -c 2.4.9 \
--ignore-current-version-compatibility-issues \
--min-issue-level=error
# Keep a report to work through
bin/uct upgrade:check /var/www/magento -c 2.4.9 --html-output-path=var/uct.html
Discussion