Drupal 9 to 10 — upgrade in five steps
If you are still on Drupal 9, the upgrade is overdue. Drupal 9 hit end of life on 1 November 2023, which means no more security fixes. Every month you stay is a month running a public site the project no longer patches. The upside: 9 to 10 is a real upgrade in place, not the rebuild that 7 to 8 was. Most sites move across in five steps. The work that eats the time is not the upgrade command itself, it is clearing the deprecated code and modules out of the way first.
We do these for clients on our Drupal support desk, so this is the order we actually run them in, with the parts that trip people up called out where they bite.
Version currency is only half the Drupal question. The other half is architecture: our take on when headless Drupal actually pays off covers whether to keep rendering in Drupal at all before you invest in the next major version.
First: 9 to 10, or straight to 11?
Answer this before you touch anything, because it changes your route. Drupal 11 is out, and you can go 9 to 11 if your contrib modules and custom code are ready for it. In practice they usually are not, and 10 is the smoother landing. Drupal 10 gives you a supported, patched site today, and the 10 to 11 hop afterward is small compared to escaping 9.
Our default is 9 to 10 first, then 11 when you are ready. Skip straight to 11 only if the site is simple, the contrib list is short, and every module already has an 11-compatible release. One caveat worth knowing: Drupal 10 has its own end of life on the horizon, expected around the end of 2026 once Drupal 12 lands, so treat 10 as a stable base you will move off again, not a final destination.
Step one: get to the latest Drupal 9.5 and PHP 8.1
You cannot jump to 10 from an old point release. Get the site onto the newest 9.5.x first, on PHP 8.1 or higher, because Drupal 10 drops support for anything older. This is also the safest place to catch problems, since you are still on a supported-path version while you sort the environment.
Bump PHP at the server level, run your database updates, and confirm the site is healthy on 9.5 before going further. If your host is still on PHP 7.4, that is its own small project, and it is a good moment to look at whether the hosting itself is holding you back.
Step two: run Upgrade Status and read it honestly
This is the step that decides whether your upgrade takes a day or a fortnight. Install the Upgrade Status module and let it scan every contrib and custom project for Drupal 10 compatibility. It gives you a colour-coded report: green is ready, yellow needs a newer release, red has no compatible version yet.
The red rows are where projects stall. A module with no Drupal 10 release means you have three choices, and none of them are the upgrade command:
- Update to a newer release of the module that supports 10, if one exists.
- Find a maintained replacement and migrate its configuration and data across.
- Drop the module if the feature is no longer worth carrying, or patch it yourself if you have the budget.
Do not paper over a red row and hope. An abandoned module with no 10 release will break the site or block the Composer update outright. We have seen upgrades sit dead for a week on a single unmaintained module that turned out to be doing something a core feature now handles anyway.
Step three: swap the deprecated pieces
Drupal 10 retired several things that were standard in 9, and each has a replacement you need to line up before the jump.
The Bartik and Seven themes are gone, replaced by Olivero for the front end and Claro for the admin. If your site runs a custom theme you are mostly fine, but if you leaned on Bartik or Seven you either switch to the new defaults or pull the old ones back in from a contrib project. CKEditor 4 is out and CKEditor 5 is in, and that migration can shift how some rich-text fields behave, so budget time to check your content. For custom code, run drupal-rector to find and auto-fix deprecated API calls; it will not catch everything, but it clears most of the mechanical work so your developers can focus on the parts that need judgment.
Step four: run the upgrade with Composer
With the red rows cleared and the deprecated pieces swapped, the actual upgrade is almost boring. Moving the content itself is a separate question, and we cover which Drupal content migration tool we reach for when a job is more move than upgrade. Update your composer.json to require Drupal 10 core and the compatible module versions, run the Composer update, then run the database updates. Use Drush 12, which is the version that pairs with Drupal 10; an old Drush is a common reason the update step throws errors that look scarier than they are.
Do this on a staging copy first, never on the live site. Take a full backup before you start, database and files both, so a bad run costs you an hour and not a weekend. If you are not sure your backups actually restore, that is worth checking before you need them, not after.
Step five: test, then go live
Walk the site before you ship it. Check content editing, the rich-text editor, every custom feature, the forms, and anything that touched a module you replaced in step two. Click through as a normal editor, not just as an admin, because permissions and editor experience are where regressions hide. Once staging is clean, schedule the production upgrade for a quiet window, put the site in maintenance mode, repeat the steps you rehearsed, and bring it back.
Then plan the next hop. You are on a supported version again, which takes the pressure off, but Drupal 10 is a waypoint, not the end of the road. Keep contrib modules current so that when 11 is the right move the jump stays small.
How long it really takes
A small site with a custom theme and a short contrib list is often a single day, most of it testing. A content-heavy site with forty contrib modules, custom code, and a few abandoned dependencies is a week or more, and almost all of that time lands in steps two and three, not the upgrade itself. Anyone quoting you a fixed price without running Upgrade Status first is guessing.
If the audit turns up red rows you do not want to untangle, or the site has been sitting unpatched long enough that you are worried about what got in, that is what we handle. Our Drupal rescue and upgrade service takes a stuck or unsupported site and gets it onto a current, patched version, and if the site has actually been compromised while running end-of-life we start with a Drupal security pass before the upgrade. Send us the Upgrade Status report and we will tell you where the real work is.
And if the audit makes you wonder whether Drupal is still the right platform at all, that is a fair question to ask at upgrade time rather than after. We put the numbers side by side in what Drupal and WordPress each cost to keep running.
Next in the journal
- 13 Jul 2026 Postfix vs Exim vs Sendmail — choosing an SMTP in 2026 Every Linux mail server runs a Mail Transfer Agent — the process that accepts a message over SMTP, queues it, and hands it to…
- 08 Jul 2026 AWS Lightsail vs a $5 VPS — when each makes sense People frame this as a price fight, and on price a plain $5 VPS wins almost every time. That is also the wrong way…