Drupal 10’s December 2026 End of Life: Why the Right Move in October Is Drupal 11

Tim Rabbetts | October 7, 2026

Drupal teams have a tempting reason to postpone an upgrade: Drupal 12 is approaching, so why move from Drupal 10 to Drupal 11 only to consider another major-version change later? In practice, that is the wrong conclusion for most production sites. Drupal 10 reaches end of life on 9 December 2026, while Drupal 12 is scheduled for the week beginning 7 December 2026. Waiting for Drupal 12 compresses the testing, remediation and deployment work into the least convenient point in the release cycle.

The safer strategy is to treat Drupal 11 as the immediate operational target and Drupal 12 as a compatibility horizon. Drupal’s own upgrade guidance requires sites to move through supported major-version paths rather than skipping the intervening upgrade, and recommends reaching a recent Drupal 11 release before moving to Drupal 12. That makes a well-tested Drupal 11 upgrade useful even if Drupal 12 is on the longer-term roadmap. ([drupal.org](https://www.drupal.org/about/core/policies/core-release-cycles/schedule?showAll=true&utm_source=openai))

What has changed in the Drupal roadmap

The recent Drupal core change records make the timing particularly important. Drupal 12 development is active, with changes being recorded for the 12.0.x branch in late September and early October 2026. The emerging release removes deprecated code, updates major dependencies and raises system requirements rather than introducing an entirely separate platform model. ([drupal.org](https://www.drupal.org/list-changes/drupal))

Several changes are already relevant to teams maintaining Drupal 10 sites:

  • Drupal 12 requires PHP 8.5.
  • Drupal 12 core development requires Node.js 24.
  • Several extensions are being removed from core or moved into contributed projects.
  • Drupal 11 is expected to receive long-term support into 2028.
  • Drupal 10 has a fixed end-of-life date of 9 December 2026.

The practical implication is that Drupal 11 is not a dead-end upgrade. It is the staging point from which a future Drupal 12 upgrade becomes more predictable. The Drupal 12 release notes specifically recommend updating to the latest Drupal 11 release before attempting the next major upgrade. ([drupal.org](https://www.drupal.org/project/drupal/releases/12.0.0-alpha1))

Why upgrading to Drupal 11 now is lower risk

You separate two different classes of work

A Drupal 10 to 11 upgrade is primarily about removing deprecated APIs, replacing extensions removed from core, updating contributed projects and ensuring that custom code works with the Drupal 11 dependency set. A Drupal 11 to 12 upgrade adds another layer: PHP 8.5, newer third-party libraries, further removals and any changes introduced during the final Drupal 12 stabilisation period.

Doing both changes at once makes failures harder to diagnose. If a deployment fails after a combined Drupal 10 to 12 jump, the cause could be a deprecated Drupal API, a removed module, a Symfony incompatibility, a PHP runtime difference, a database requirement or an extension that has not yet declared support. Moving to Drupal 11 first gives the team a known, supported baseline.

You gain operational experience with the current upgrade path

The Drupal 10 to 11 documentation is now mature and was updated as recently as 21 August 2026. It identifies Drupal 10.3 as the minimum source version, requires PHP 8.3 or later, and documents the Composer and Drush workflow. ([drupal.org](https://www.drupal.org/docs/upgrading-drupal/upgrading-drupal/how-to-upgrade-from-drupal-10-to-drupal-11))

That means teams can perform the first upgrade using established guidance, existing contributed releases and a broad set of community-tested solutions. The work also produces a useful inventory of custom code, patches, scaffold changes and deployment assumptions before Drupal 12 raises the platform requirements again.

You avoid an end-of-life deadline becoming a release plan

An end-of-life date should be treated as a compliance boundary, not as a target deployment date. Production upgrades routinely uncover issues that do not appear in a basic Composer update: a custom plugin may rely on a deprecated service, a theme may contain obsolete libraries, a search implementation may expose cache problems, or a deployment script may assume that writable settings files remain in place.

Allowing several weeks between the Drupal 11 deployment and the Drupal 10 deadline gives the team time to observe cron, queues, cache behaviour, search indexing, editorial workflows and external integrations under normal traffic.

Establish the current state before changing Composer

Start with a reproducible inventory. Do this in a development environment or a fresh copy of the production codebase, not directly on the live server.

php --version
composer --version
drush status
drush core:status
drush pm:list --status=enabled --type=module,theme
composer show --direct --name-only

Record the output in the upgrade ticket or repository. In particular, capture the current Drupal core version, PHP version, database engine, Drush version, enabled modules, active theme, PHP extensions and any Composer patches.

For a Composer-managed project, commit the current state before starting:

git status
git checkout -b upgrade/drupal-11
git add composer.json composer.lock web/sites
git commit -m "Baseline before Drupal 11 upgrade"

Do not commit production secrets simply because you are creating a baseline. Most projects should keep sensitive settings outside the repository or use environment-specific settings files. The important point is to create a recoverable code state, not to copy credentials into version control.

Check the source version

Drupal 10 sites must be running Drupal 10.3.0 or later before upgrading to Drupal 11. Older update paths were removed from Drupal 11, so a site on an earlier 10.x minor release should first be updated within Drupal 10. ([drupal.org](https://www.drupal.org/docs/upgrading-drupal/upgrading-drupal/how-to-upgrade-from-drupal-10-to-drupal-11))

Use the normal update process to reach the latest secure Drupal 10 release available to the project, then run database updates and export configuration before beginning the major-version work.

composer update "drupal/core-*" --with-all-dependencies
drush updatedb
drush cache:rebuild
drush config:export
git add composer.json composer.lock config/sync
git commit -m "Update Drupal 10 before major-version upgrade"

Do not blindly update every package in a long-lived project and assume the result is a useful baseline. If unrelated dependency changes enter the same commit, diagnosing an upgrade regression becomes more difficult. Keep the update scope visible in the commit history.

Audit removed and obsolete extensions

Drupal 11 removes several extensions that were previously shipped with core, including Actions UI, Activity Tracker, Book, Forum, Statistics and Tour. Single Directory Components and Help Topics are also identified as obsolete because their functionality has moved elsewhere or their project status has changed. ([drupal.org](https://www.drupal.org/docs/upgrading-drupal/upgrading-drupal/how-to-upgrade-from-drupal-10-to-drupal-11))

Find out whether any of those extensions are enabled or referenced by configuration:

drush pm:list --status=enabled --type=module,theme
drush config:get core.extension module
drush config:export --destination=/tmp/drupal-config-before-d11

For each removed extension, choose one of three deliberate options:

  1. Remove the feature and its configuration because it is no longer needed.
  2. Install the supported contributed replacement before changing the Drupal core major version.
  3. Replace the feature with a different implementation and migrate its configuration or content.

The order matters. If a module is still required by configuration when Drupal 11 is installed, the upgrade may fail or leave the site with missing-extension errors. If a contributed replacement exists, add it to Composer while the site is still on Drupal 10, enable it, verify the configuration and only then perform the core upgrade.

Do not uninstall a module merely because its code is being moved from core to contrib if the module owns configuration or content. Confirm the replacement’s migration path first. Drupal’s Drupal 12 guidance makes the same point for extensions removed from core: require the contributed version before upgrading where the functionality remains necessary, rather than deleting configuration accidentally. ([drupal.org](https://www.drupal.org/project/drupal/releases/12.0.0-alpha1))

Use Upgrade Status as a filter, not as a verdict

Upgrade Status is useful for locating deprecated APIs in custom and contributed code, but its report is not a substitute for testing. A clean report does not prove that a module behaves correctly on real content, and a warning does not always mean that an upgrade blocker exists.

Install it in a development environment, run its checks and treat every result as an item for triage:

composer require drupal/upgrade_status --no-update
composer update drupal/upgrade_status --with-all-dependencies
drush en upgrade_status -y
drush cr

For custom modules and themes, combine Upgrade Status with Drupal Rector where appropriate. The goal is not to mechanically replace every deprecated call. First understand what the code is doing, then apply the current API and add or update tests.

Prioritise findings in this order:

  • Code executed on every request, such as event subscribers, services and route access checks.
  • Authentication, authorisation and entity-access code.
  • Update hooks and post-update functions.
  • Custom field, Views, queue and migration plugins.
  • Theme preprocess functions and JavaScript behaviours.
  • Test-only code and development tooling.

Access-control code deserves particular attention. A deprecation fix that changes a service, route requirement or entity query can accidentally alter who can see or modify content. Add a regression test for sensitive routes rather than relying solely on manual browser testing.

Prepare the Composer upgrade

Once contributed and custom-code blockers have been addressed, update the core package constraints without resolving the entire dependency graph immediately:

composer require \
  'drupal/core-recommended:^11' \
  'drupal/core-composer-scaffold:^11' \
  'drupal/core-project-message:^11' \
  --no-update

If the project explicitly requires drupal/core, remove that direct requirement when using the recommended project packages. Also update Drush and development dependencies in a controlled way:

composer remove drupal/core --no-update
composer require drush/drush --no-update
composer require 'drupal/core-dev:^11' --dev --no-update

The Drupal upgrade documentation notes that Drupal 11.4 adds symfony/runtime as a dependency and that Composer may require explicit permission for the plugin. Configure that permission only if the project’s dependency review approves it:

composer config allow-plugins.symfony/runtime true

Run the resolver before making changes to the lock file:

composer update --dry-run

If Composer reports a conflict, do not immediately delete composer.lock or the vendor directory. Identify the package preventing the upgrade:

composer why-not drupal/core ^11
composer prohibits drupal/core ^11

Then inspect the package’s Drupal.org project page and issue queue. Common solutions include requiring a newer module release, removing an abandoned package, replacing a patch with an upstream release, or adjusting a direct dependency constraint. The Drupal documentation specifically recommends checking for Drupal 11-compatible releases and reviewing project issue queues where compatibility is incomplete. ([drupal.org](https://www.drupal.org/docs/upgrading-drupal/upgrading-drupal/how-to-upgrade-from-drupal-10-to-drupal-11))

Run the upgrade in an isolated copy

A reliable rehearsal needs more than the production codebase. Restore a recent database backup, copy public and private files where appropriate, and ensure that environment-specific settings point to safe services. Disable outbound email or route it to a capture service so that test submissions cannot contact real users.

Before running database updates, make the settings files writable only as much as your deployment process requires. The Drupal documentation includes a temporary permission change for the upgrade process; restore restrictive permissions afterwards. ([drupal.org](https://www.drupal.org/docs/upgrading-drupal/upgrading-drupal/how-to-upgrade-from-drupal-10-to-drupal-11))

chmod u+w web/sites/default
chmod u+w web/sites/default/*settings.php
chmod u+w web/sites/default/*services.yml

composer update "drupal/core-*" drush/drush --with-all-dependencies
composer install

drush updatedb:status
drush updatedb
drush cache:rebuild

Where possible, prefer a deployment pipeline that builds the Composer artefacts once and promotes the same build through testing and production. Running composer update directly on a production server makes the deployment dependent on network availability and the package repository’s state at that exact moment.

After the database updates complete, export configuration and inspect the diff:

drush config:export
git diff -- config/sync
drush status
drush watchdog:tail

Unexpected configuration changes are not automatically wrong, but they must be understood. Pay particular attention to enabled extensions, text formats, roles and permissions, Views, image styles, search configuration and third-party integration settings.

Test behaviour, not just the status report

Build a test matrix around the site’s actual risk profile. At minimum, cover:

  • Anonymous and authenticated page delivery.
  • Login, password reset, account editing and role-specific access.
  • Content creation, editing, moderation and revision workflows.
  • Media uploads, image styles and private files.
  • Forms, Webform submissions and confirmation emails.
  • Search, exposed Views filters, facets and pagination.
  • Multilingual content and translated configuration.
  • Cron, queues, scheduled publishing and search indexing.
  • JSON:API, REST, GraphQL or other external API consumers.
  • Commerce, payment, CRM, identity-provider and analytics integrations.

For custom code, run the project’s automated tests and fail the build on new deprecations where practical. For example:

vendor/bin/phpunit -c web/core/phpunit.xml.dist
vendor/bin/phpcs --standard=Drupal,DrupalPractice web/modules/custom web/themes/custom
drush cron
drush queue:run

Use the commands that exist in the project’s installed Drush version and test suite; do not copy a command into production without checking the local toolchain. A project may use a custom PHPUnit configuration, Behat, Cypress, Playwright or a CI-specific wrapper instead of the examples above.

Check caches and performance

Major-version upgrades can expose cache-context mistakes that are invisible when browsing as an administrator. Test pages as anonymous users, users with different roles and users with different language or site-section access. Check response headers and confirm that personalised content is not being served from a shared cache.

Also observe slow queries and queue backlogs after deployment. A successful database update does not prove that a large content site will complete cron within its operational window.

Plan the production deployment

Use a maintenance window appropriate to the site’s traffic and database size. The deployment should have a clear order:

  1. Put the site into maintenance mode or otherwise prevent writes.
  2. Enable database backups and verify that the backup completed.
  3. Deploy the tested code and Composer artefacts.
  4. Run database updates and rebuild caches.
  5. Import configuration only if configuration deployment is part of the release.
  6. Run smoke tests as anonymous and authenticated users.
  7. Re-enable traffic and monitor logs, queues and external integrations.
drush state:set system.maintenance_mode 1
drush cache:rebuild

drush updatedb -y
drush config:import -y
drush cache:rebuild

drush state:set system.maintenance_mode 0
drush status
drush watchdog:tail

Whether configuration import belongs before or after database updates depends on the project’s deployment conventions and the changes being released. Keep the sequence consistent with the tested rehearsal rather than adopting a generic order without validation.

Have a rollback plan that reflects Drupal’s database behaviour. Reverting PHP files alone is not a complete rollback if database updates have already run. A proper rollback may require restoring the database and files from coordinated backups, or correcting forward with a follow-up deployment. Document that distinction before the maintenance window begins.

Use Drupal 11 to prepare for Drupal 12

Once the Drupal 11 upgrade is stable, start a separate compatibility branch for Drupal 12. Do not test an alpha or beta release on the production site. Drupal’s early Drupal 12 release notes explicitly state that alpha releases are for compatibility testing and should not be used in production. ([drupal.org](https://www.drupal.org/project/drupal/releases/12.0.0-alpha1))

Start by tracking the requirements that could affect infrastructure:

  • PHP 8.5 availability across local, CI, staging and production environments.
  • Node.js 24 for front-end asset workflows and core development tooling.
  • Database versions supported by the final Drupal 12 requirements.
  • Contributed replacements for extensions removed from core.
  • Custom code that still emits deprecation warnings on Drupal 11.

Do not upgrade the production runtime simply because a future Drupal version will require it. Instead, add a PHP 8.5 job to CI, build a disposable environment and test the application with the same infrastructure assumptions that Drupal 12 will need.

Drupal 12 development is also changing the status of familiar core components. The current change records identify removals or deprecations involving Search, Toolbar, Claro and Olivero, among others. The exact replacement or migration action depends on how a site uses each component, so treat the change records as an audit list rather than a universal uninstall instruction. ([drupal.org](https://www.drupal.org/list-changes/drupal))

Common mistakes to avoid

Waiting for Drupal 12 before doing any work

This converts a manageable upgrade into a deadline-driven programme. Even if Drupal 12 is the final target, the Drupal 11 upgrade remains valuable preparation and is the supported intermediate path.

Using a compatibility flag as a permanent solution

Lenient Composer configuration or a temporary patch can help a team test a dependency, but it should not hide an unsupported module in production. Record every patch, its upstream issue and the condition for removing it.

Testing only the homepage

Drupal failures often occur in administrative workflows, queue workers, cron, private files, multilingual routes and integrations. Test the capabilities that make the site valuable, not only the pages that are easiest to browse.

Changing PHP, Drupal and the database simultaneously

Infrastructure upgrades may be necessary, but bundling every change into one deployment removes diagnostic clarity. Where possible, establish a supported PHP baseline first, then upgrade Drupal, then plan the next runtime or database change as a separately observable step.

Forgetting deployment-owned files

Drupal core scaffold files, including .htaccess, can change during a major upgrade. If the project has customised scaffold files, document those changes and reapply them deliberately rather than allowing the upgrade to overwrite them unnoticed. ([drupal.org](https://www.drupal.org/docs/upgrading-drupal/upgrading-drupal/how-to-upgrade-from-drupal-10-to-drupal-11))

The October decision

For a Drupal 10 site, the decision in October 2026 should be straightforward: begin the Drupal 11 upgrade now unless there is a documented, tested reason not to. Reach at least Drupal 10.3, audit removed extensions, resolve contributed-module constraints, modernise custom code and rehearse the deployment against a production-like database.

Then use Drupal 11 as the stable platform for observing Drupal 12 development. Add PHP 8.5 and Node.js 24 to your compatibility planning, follow the Drupal core change records, and keep future upgrade work separate from the production migration. This approach turns Drupal 12 from an emergency deadline into a controlled follow-on project.

The most important deliverable is not the Composer command that changes the version constraint. It is the evidence that the site can be upgraded, tested, deployed and operated safely. A Drupal 11 deployment completed well before 9 December 2026 provides that evidence while there is still time to fix what the test environment reveals.