Drupal 9 is scheduled to be released on June 3, 2020. What this means to you has been extensively covered in the Driesnote at DrupalCon Amsterdam 2019. Now, how do you go about actually getting the job done and removing deprecated APIs from contributed modules you're using? There are several tips I'd like to share here. Nothing breathtaking, but rather a systematic approach to ensuring you'll stay on top of things so your apps are ready on the day of the Drupal 9 release.
Before we get started, here are a few resources you might find useful:
The challenge in front of you is not technical as most API changes involve only a few lines of code. Rather, your mission is to start planning ahead now. As of the writing of this blog post, you have about 7 months to be ready. This might seem like a lot, but there are several factors to take into account:
To get organized, I'd suggest you leverage your issue tracker of choice and write down bite-sized chunks of work you can easily slide into sprints. Here's an example :
Here, I'm using a Jira EPIC called âPrep for Drupal 9' which is meant to track one issue per custom or contributed module I know is using deprecated APIs. Your strategy might be different whether you maintain only one app or many and you want to abstract out popular contrib modules in their own EPIC because they have the potential to impact most/all apps you're responsible for. The reason why I insist on breaking things down into dedicated issues is not all contrib modules are created equal and will be ready at the same time. As we split up the work into chunks, we can then make decisions based on information at hand around the day of the Drupal 9 release. Those decisions can be formulated like so:
There are times when you are blocked from removing APIs that are dependent on a minor version EOL or an upcoming minor release. This is the case of Facets and Google Analytics in the above example and it needs you to carefully think about the implications. As an example, if you maintain a contrib module and you remove an API that was deprecated in 8.8.x but your user base might still be running on a previous Drupal core minor version that is still being maintained by the Drupal Security Team, then you risk breaking their apps. As a responsible module maintainer, you should do the right thing, but only at the right time.
It's easy to think about what you have to do, but it's not so easy to determine how you're going to do it. Let's step back to understand what your next step should be when interacting with the community. Here's a flowchart I came up with. I'll explain the top-right composer.json patching circle in a moment.
You can see above I'm not using the Upgrade Status module but a CLI alternative called Drupal Check. It's a customized runner for PHPStan which allows you to conveniently check Drupal deprecation rules. It's also the perfect companion for your CI/CD integration. Check it out.
A typical way to track progress for individual issues is to mimic how you'd work in the public Drupal issue queue. Post comments to keep the team in the loop about your work, and often update the issue summary for those who can't afford to read many comments. Do note that in the screenshot below there's a caption indicating when the check was last performed, which is always convenient to know about.
You should always keep in mind it's critical to track your work on drupal.org as this makes it possible for others to get involved. That being said, for your own tracker, another useful thing to do is to link to drupal.org issues so you always know what remains to be done for a module to be ready for Drupal 9 without leaving your workspace.
Did you notice that the linked Jira issues are rendered like issues on drupal.org? This is thanks to the Drupal Issue Chrome extension which greatly improves the UX on non-drupal.org pages and doesn't force you into clicking on the links to see if there was any status change to any of the linked issues.
Finally, here's a typical comments section. Remember you're not posting comments for yourself but for others (or your future self) to see the detailed history, should you have to come back to this at some point in the future. It's like writing a good Git commit message, right?
If you're still not managing your site via Composer, do it now. I can't stress this enough. There are multiple ways to help you switch to a Composer-managed install (composerize-drupal, Composerize, drupal composerize's Drupal Console command...) and there's even a core issue that is discussing ways to help you safely do it with a community-approved solution. Note that at this point the community seems to be leaning towards leveraging composerize-drupal.
If you're still not convinced, here's one more reason: when it comes to removing deprecated APIs, sometimes things will be outside your control and it's not a great feeling to be blocked by others. Remember the above flowchart and the top-right composer.json patching circle? This is my opinionated way to think about putting you back in control: while you might file an issue, post or review a patch, beg the maintainer to commit it and hope for a new release to be tagged ASAP, sometimes expectations won't be met and you'll need Composer to help you out.
Composer is a fantastic asset. Out of the many great things it does, it can be extended to safely patch your application without hacking core. And we're going to leverage this opportunity with deprecated APIs. Here's an example where we're updating composer.json to include several patches from drupal.org:
,
"patches": { "drupal/slack_receive": { "3053951 - Anchor tags stripped from markdown response in slack": "https://www.drupal.org/files/issues/2019-05-14/slack_receive-markdown-title-3053951-4.patch" }, "drupal/extlink": { "3042607 - JavascriptTestBase is deprecated in favor of WebDriverTestBase": "https://www.drupal.org/files/issues/2019-07-24/extlink-fix-deprecation-3042607-4-d8.patch", "3029176 - Replace usages of the deprecated drupal_set_message() function": "https://www.drupal.org/files/issues/2019-01-29/extlink-Replace_usages_of_the_deprecated_drupal_set_message_function-3029176-2-D8.patch" }, "drupal/autosave_form": { "3086690: entity_get_form_display() is deprecated and should be removed": "https://www.drupal.org/files/issues/2019-10-09/deprecated-3086690-2.patch", "3067893: Remove deprecated JavascriptTestBase in favor of WebDriverTestBase": "https://www.drupal.org/files/issues/2019-08-09/3067893-4.patch" }, "drupal/google_analytics": { "3034176: Use mb_* functions instead of Unicode::* methods": "https://www.drupal.org/files/issues/2019-02-27/3034176-5.patch" }, "drupal/crop": { "3042587: Remove deprecated function calls and raise the minimum version of core to 8.7": "https://www.drupal.org/files/issues/2019-10-17/crop_api-3042587-15.patch", "3042587: Follow-up to #3042587": "https://www.drupal.org/files/issues/2019-10-18/missing-file_unmanaged_copy-removal.patch" }, "drupal/contact_storage": { "3081195: Remove calls to entity_get_display() and entity_get_form_display()": "https://www.drupal.org/files/issues/2019-10-12/2-contact-storage-drupal9-compatibility.patch" }, "drupal/consumers": { "3042825: Drupal 9 Deprecated Code Report": "https://www.drupal.org/files/issues/2019-05-20/deprecated_code-3042825-2.patch" }, "drupal/memcache": { "3042707: Drupal 9 Deprecated Code Report": "https://www.drupal.org/files/issues/2019-04-02/drupal_9_deprecated_code_report-3042707-2.patch" }, "drupal/image_widget_crop": { "3042648: Drupal 9 Deprecated Code Report": "https://www.drupal.org/files/issues/2019-03-26/image_widget_crop-fixed_drupal_set_message-3042648-2.patch" }},
,
In conclusion, you should be in a good position to track your work, contribute patches to drupal.org and leverage composer.json to apply patches today. For your convenience we've built a deprecation status tool in the Acquia Developer Center (Gábor even published a video about it). We hope you like it!
If this content did not answer your questions, try searching or contacting our support team for further assistance.
Fri Sep 12 2025 08:21:49 GMT+0000 (Coordinated Universal Time)