Applies to Joomla 3.10 / 4.4 → 5.4 (and on to 6.x) · shell access recommended Updated 16 Oct 2026

This is the order of work we use to move a Joomla 3 or 4 site to Joomla 5.4, written as a runbook: what to run, what to check after each step, and the problems that cost us time on real migrations. The last section covers the next jump, 5.4 → 6, from the command line, the way we upgraded our own site.

Step 0: Inventory and a staging copy

Never migrate the live site. Copy it, files and database, to a staging host with the target PHP version, and write down what you are starting from:

# terminal – on the copy
grep -E "MAJOR_VERSION|MINOR_VERSION|PATCH_VERSION|RELEASE|DEV_LEVEL" libraries/src/Version.php
php -v
mysql -e "SELECT type, element, folder, enabled,
                 JSON_UNQUOTE(JSON_EXTRACT(manifest_cache, '$.version')) AS version
          FROM jos_extensions
          WHERE JSON_UNQUOTE(JSON_EXTRACT(manifest_cache, '$.author')) NOT LIKE 'Joomla%'
          ORDER BY type, element;" mydb > extensions-before.txt

For every line in extensions-before.txt, decide: update (a Joomla 5 version exists), replace (abandoned, an alternative exists), or remove (not used). Disabled extensions are the easiest wins. Uninstall them before you start, and the migration has fewer moving parts.

On staging, also turn off outgoing mail and put payment plugins in test mode. Scheduled tasks and cron jobs on a copy will otherwise mail real customers.

Step 1 (Joomla 3 only): 3.10 → 4.4

This is the expensive step, because Joomla 4 rewrote the core.

  1. Update to the last 3.10. In Joomla Update, the Pre-Update Check tab lists every extension with "compatible / not compatible / unknown" for Joomla 4, and checks PHP and database versions.
  2. Switch the template to Cassiopeia on staging before the update. A Joomla 3 template will not render on Joomla 4. It gets rebuilt anyway, and a working default template makes the result testable.
  3. Run the update to 4.4 through Joomla Update ("Upload & Update" with the 4.4 update package if the channel doesn't offer it).
  4. Fix the database schema: System → Maintenance → Database. Every row must say "up to date". If one doesn't, press "Update Structure" and read what it reports.
  5. Rebuild the template for Joomla 4/5 (Bootstrap 5, the Web Asset Manager, new layout overrides). Copying old overrides across is the most common source of broken pages after a migration.

Content, users, menus and categories come across reliably. In our experience, what breaks is everything around them: custom template overrides, editors' inline HTML that relied on Bootstrap 2 classes (span6, pull-right), and extensions that store HTML with old markup.

# terminal – find Bootstrap 2/3 classes in article HTML that will lose their styling
mysql -e "SELECT id, title FROM jos_content
          WHERE introtext REGEXP 'class=\"[^\"]*(span[0-9]+|pull-(left|right)|offset[0-9]+|hidden-phone|visible-desktop)'
             OR \`fulltext\` REGEXP 'class=\"[^\"]*(span[0-9]+|pull-(left|right)|offset[0-9]+)';" mydb

Step 2: 4.4 → 5.x with the compatibility plugin

From 4.4 the jump is an update, not a migration. Joomla 5 ships Behaviour – Backward Compatibility, which keeps Joomla 4 code that uses deprecated APIs running.

  1. Update every extension to its newest version for Joomla 4 first. Most vendors released versions that run on both 4.4 and 5.
  2. Check PHP 8.1+ (8.3 if you're going on to Joomla 6).
  3. Run Joomla Update → 5.x. Check System → Maintenance → Database again.
  4. With Log Deprecated API on (Global Configuration → Logging), click through the site and read administrator/logs/deprecated.php. That file is your to-do list for Joomla 6.

Step 3: 5.x → 5.4 and leave the site there for a while

Update to the latest 5.4.x, re-test, and go live. Joomla 5.4 has security support until October 2027. A site that is cleanly on 5.4 with an empty deprecation log is in the best possible position for Joomla 6, and you've only changed one thing at a time.

Going on to Joomla 6 from the command line

We upgraded our own site from 5.4 to 6.2 with the Joomla CLI. It's faster than the browser for big sites and doesn't hit PHP time limits. The commands:

# terminal – on staging, with a backup you have restored once
php cli/joomla.php core:update:check
php cli/joomla.php core:update                    # latest 5.4.x first
php cli/joomla.php core:update:channel next       # offer the next major version
php cli/joomla.php core:update                    # → 6.x
php cli/joomla.php update:joomla:remove-old-files
php cli/joomla.php maintenance:database           # must report every table as up to date
php cli/joomla.php cache:clean

What we hit on the way, and what you are likely to hit too:

  • The CLI itself crashed before the update started. The CLI application boots enabled plugins, and plugins whose entry file still uses J* class names fail when they load. We disabled those plugins (in our case 112, from three commercial extensions) for the upgrade only, then re-enabled them. Joomla also asks you to disable the old Joomla 5 compatibility plugin before the major update.
  • The finalisation step failed after the files were replaced, because the running process still had Joomla 5 classes in memory. Running finalisation again with the new code, and then maintenance:database, completed it cleanly. Check the schema report. "Files updated" is not "upgrade done".
  • Extensions that need old class names ran again once "Classes Aliases" was turned on in Behaviour – Backward Compatibility 6. It's off by default.
  • Case-insensitive file systems. On macOS (our local copies), an extension update that renamed folders from classes/ to Classes/ deleted the new folder together with the old one. Linux servers are fine, but test locally on a case-sensitive volume or expect surprises.

The checks we run after every step

CheckHow
Schema up to dateSystem → Maintenance → Database, or maintenance:database
No PHP errorsweb server error log, with Error Reporting at "Maximum" on staging
Deprecationsadministrator/logs/deprecated.php
Every page type rendershome, category blog, article, contact form, search, login, 404, every component's main views
Forms sendcontact, registration, password reset; check the mail catcher
OverridesSystem → Templates → "Changes found" notices
URLs unchangedcrawl the old sitemap against staging; every URL should be 200 or a deliberate 301

The last row matters more than it looks. Router and menu changes during a migration can quietly change URLs, and rankings go with them. A crawler that takes a URL list as input (Screaming Frog, or wget --spider -i urls.txt) finds them in minutes.

When it goes live

  1. Freeze content on live (or note what changes during the switch).
  2. Take a final backup of live.
  3. Deploy staging to live, with live's configuration.php values (database, paths, mail, live site URL).
  4. Clear all caches, including the CDN, and check the same list again on live.
  5. Keep the old live backup for at least a month.

If the site runs a shop or a CRM, it has its own upgrade path on top of this one: see VirtueMart 3 to 4.8 on Joomla 5 and upgrading a Joomla site with CiviCRM.