Legacy code
Older custom or contributed code that targets APIs Drupal has deprecated or removed, and so blocks or complicates the next major upgrade.
Legacy code is code that was written for an older Drupal version, an older API or an older way of doing a task and is still in use. Drupal core flags such code with deprecation notices, and public APIs keep working until the major release that removes them.
How Drupal marks old code
Core follows a deprecation policy. Public code is deprecated in one release and removed in a later major release; the policy allows internal code to be removed in a minor release. It also says that modules and themes in core can be deprecated and removed in the next major release. A deprecation carries a PHPDoc tag in the form @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0, and a matching @trigger_error() call with E_USER_DEPRECATED that fires when the old path runs. The policy says the @ suppression should be used in most cases, so that core can customize the error handling.
Drupal 11 also gives its own name to old code. The #[LegacyHook] attribute marks a procedural hook function kept next to a newer attribute-based implementation, so a contributed module can support Drupal 11 and older versions together. The hook system still collects procedural implementations.
Why dates matter
The release schedule on Drupal.org, dated 27 August 2026 and checked on 2026-10-26, says Drupal 10 reaches end of life on December 9, 2026 and that Drupal 12 is planned for the week of December 7, 2026. Code that still relies on APIs removed in Drupal 12 will need work before a site can move there. Drupal.org's upgrade guide describes its Drupal 6 and 7 section as upgrading from a legacy Drupal 6 or Drupal 7 site, and its pages for that path cover the migrate modules and customizing migrations.
Example
This notice comes from Connection::query() in Drupal core 11.4.10. It fires when custom code passes an integer fetch mode:
$connection->query($sql, $args, ['fetch' => \PDO::FETCH_OBJ]);
Core reports that passing the fetch key as an integer is deprecated in drupal:11.2.0 and removed from drupal:12.0.0, and tells you to use a case of the FetchAs enum instead. The query still runs on Drupal 11. The fix is a one-line change in the custom module.
Common mistakes
- Ignoring deprecation notices. They are the early warning. Silencing them leaves the break for upgrade day.
- Testing only on the current version. A module that works on Drupal 11 can still call code that Drupal 12 removes.
- Treating contributed modules as someone else's problem. The Upgrade Status project flags contributed projects that need updates, not only custom code.
For marketing and content teams
Legacy code is invisible on the page and expensive later. When an agency quotes a major Drupal upgrade, ask how much custom code was flagged by an automated scan and how much of it was rewritten. A site with little custom code and up-to-date modules has little to rewrite, and a plan with a date helps you budget.
Sources
- Drupal.org: Drupal deprecation policy (checked 2026-10-26)
- Drupal.org: Release schedule (page dated 27 August 2026, checked 2026-10-26)
- Drupal.org: Upgrading Drupal (checked 2026-10-26)
- Drupal.org: Upgrade Status project (checked 2026-10-26)
- Drupal core 11.4.10: Database Connection class
- Drupal core 11.4.10: LegacyHook attribute