Install
To start a new Drupal project with version 9.0.0:To update your site and all dependencies to the latest version of Drupal:
To update your site to this specific release:
Using Composer to manage Drupal site dependencies
Downloads
Release notes
This is the first supported release of the new Drupal 9 major version, and it is ready for use on production sites! Learn more about Drupal 9 and the Drupal 8 and 9 release cycles.
Drupal 9.0.0 has been released simultaneously with Drupal 8.9.0. Drupal 8.9 is a long-term support version that will be supported until November 2021, with no new feature development (whereas Drupal 9 development and support will continue beyond that date). Drupal 8.9 has most of the changes that Drupal 9 does, but retains backwards compatibility layers added through Drupal 8's release, and is a good choice to update to first if you have an existing Drupal site, to ensure maximum compatibility and the smallest necessary changes for the Drupal 9 update.
If you are starting a new Drupal 9 project, you have a choice between Drupal 8.9 and 9.0, and generally want to choose Drupal 9.0 for forward compatibility with later releases.
Regardless of which version you choose now, features will only be added to Drupal 9 minor releases, so plan to be on Drupal 9 this year so that you can easily update to Drupal 9.1 and later.
Refer to How to prepare your Drupal 7 or 8 site for Drupal 9 for tools you can use to check the Drupal 9 compatibility of modules, themes and sites.
Both 9.0.0 and 8.9.0 include all the latest commits, and they have the same APIs and features. This also means modules and themes can be compatible with Drupal 8 and 9 at the same time! The key changes in 9.0 are:
- Deprecated code has been removed.
- Dependencies have been updated to new major versions as appropriate.
- Platform requirements (supported PHP and database versions) have been increased.
For all other changes, refer to the 8.9.x branch.
Important update information
Updating from Drupal 8
For information on updating from Drupal 8 to Drupal 9, see Upgrading a Drupal 8 site to Drupal 9.
Sites on 8.7 or earlier must update to either 8.8 or 8.9 before updating to Drupal 9 as all Drupal 8 update functions from before Drupal 8.8.0-rc1 were removed from Drupal 9. We recommend updating to 8.8.7 or 8.9.0, as well as updating all contributed modules, before updating to any Drupal 9 release.
The migration paths from Drupal 6 and Drupal 7 to Drupal 9 will remain supported throughout Drupal 9's release cycle.
Note for users of the Experimental Workspaces module
Existing Drupal 8 sites using the experimental Workspaces module must update to at least Drupal 8.8.2 before updating to Drupal 9. (This is due to a required data integrity fix.) Remember that Workspaces is currently in beta status and is not intended for production.
Upgrading from Drupal 7
Drupal 7 users can continue to migrate to Drupal 8.8 or 8.9, or migrate to 9.0 directly. The upgrade path for multilingual sites is stable in Drupal 9.0.0, 8.9.0, and 8.8.7!
Server and database requirements
Drupal 9 requires PHP 7.3 or higher, and the version requirement for Apache has been increased to Apache 2.4.7 or higher. The following database versions are supported by Drupal 9 core:
- MySQL or Percona 5.7.8.
- MariaDB 10.3.7 (Note that this is a more recent release than the MySQL version.)
- PostgreSQL 10 with the pg_trgm extension.
- SQLite 3.26 (PHP does not always use the system-provided SQLite, so verify that your PHP is compiled with at least this version).
A MySQL contributed database driver is available to provide support for older supported versions of MySQL, Percona, and MariaDB until their end of life, and a similar PostgreSQL contributed database driver provides support for PostgreSQL 9.6. (Be sure to review these drivers' project information before installing one.)
Database driver handling improvements
-
The default database is now checked when Drupal is updated to ensure it complies with the minimum version supported by the database driver. (Previously, this only happened during installation.) Updates will not proceed if the requirement is not met.
If you see an error about your database version when running
update.php
, ensure your database meets the minimum database requirements or install one of the legacy database drivers provided as contributed projects. -
Database drivers provided by modules can now be placed in
src/Driver/Database
. These drivers will be listed in the installer. Existing custom or contributed drivers do not need to make any changes and will continue to work as before. -
The databases supported by Drupal 9 core all have JSON support. Future minor releases of Drupal 9 may take advantage of that JSON support. Maintainers of contributed database drivers are encouraged to monitor that issue to see how that will impact them. Change records and release notes will be added for releases that introduce those changes.
Removal of Drupal 8's deprecated APIs
All code that was marked deprecated in Drupal 8 has been removed from Drupal 9.0.0. Many contributed modules are already Drupal-9-compatible; however, you should use Upgrade Status on a fully up-to-date Drupal 8.8 or Drupal 8.9 site to check for issues in your contributed projects and custom code, before attempting to update to Drupal 9.
Update system improvements and upgrade path fixes
-
Drupal now shows a more user-friendly warning when a site tries to upgrade to a new version without having run required intermediate database updates first.
If you see 'Unsupported schema version' when attempting to run updates, you should:
- Back up your site and codebase.
- Locate an older version of the contributed module which contains the updates you missed.
- Downgrade the module to that version in your code base, and attempt to run updates again.
When this error is shown, it will now also prevent any updates from proceeding, so may make a persistent issue on an existing site more obvious.
Ideally, you should always attempt updates of contributed modules and core on a backup of your site (such as a local development environment) prior to running them on production.
-
Drupal 9 will halt an attempted update from Drupal 8 if the Drupal 8 site has missing or incompatible modules, missing updates from core or contrib modules, or certain types of data integrity issues. In these cases a clear error message will be shown, and you should fix the errors on your Drupal 8 site prior to attempting an update again. Several critical upgrade path bugs that affected updates to 8.8 or later have been fixed in both Drupal 8.8 and Drupal 8.9.
-
The Views configuration fixes previously applied as post-updates in #2846614: Incorrect field name is used in views integration for multi-value base fields are now applied at every Views save in order to resolve an upgrade path bug. The old configuration structures are now formally deprecated in 9.0.0 and will be removed from 10.0.0. For more information on the changes that introduced this in previous releases, see the related change records:
Migration system improvements
The migration path from Drupal 6 and Drupal 7 to Drupal 8 or 9 is stable, including multilingual migrations and many features which were moved into core for Drupal 9. Drupal 9 contributed modules are responsible for providing their own migrations into Drupal 9 and this is something to audit during the process of migrating a Drupal 6 or 7 site. Read more on Upgrading from Drupal 6 or 7 to 8 and newer.
-
Multilingual migrations are now stable and have been moved into the main Migrate Drupal module. The experimental Multilingual Drupal Migrate module is therefore no longer required, and will be uninstalled automatically on upgrade.
-
A new 'complete node migration' is now available and will migrate all nodes and node revisions, including translated nodes and the translated node revisions. The complete node migration is named
d*_node_complete.yml
(where*
is the major version, 6 or 7) will eventually replace the existing trio of node migrations,d*_node
,d*_node_revision
, andd*_node_translation
. See the change record on the complete node migration for more information. -
Drupal 7 Entity Translation revision migrations for nodes are now supported.
Contributed project versioning improvements
Contributed modules may now declare compatibility with multiple major versions of core (so the same module codebase can be compatible with Drupal 8 and 9 at the same time. Furthermore, semantic versioning is also now supported for contributed projects, so Drupal 9-compatible modules may have versions in patterns like either (e.g.) 8.x-3.2 or (e.g.) 4.0.7. For more information on module versions in Drupal 9, review the change record on our semantic versioning support.
Render array hardening against remote code execution
The security fixes required for SA-CORE-2018-002 and SA-CORE-2018-004, as well as other publicly disclosed security issues, all indicated that the render system needs to be stricter about what may be called by a callback. If you have code that adds a render callback (#access_callback, #lazy_builder, #pre_render
or #post_render
), it might need to be updated to work in Drupal 9. Read more in the change record for limitations on what can be called by a callback in render arrays.
Removed core modules
-
The Place Blocks experimental module has been removed from core. (It was already hidden with no further development since Drupal 8.6.0, and was formally deprecated in Drupal 8.8.0). See the change record on Place Blocks for replacement suggestions.
-
The SimpleTest module has been moved to contrib, and Drupal core no longer runs SimpleTest as part of its test suite. Automated tests should be written and run using PHPUnit. Modules that still have legacy SimpleTest tests can customize their drupalci.yml to continue running SimpleTests while upgrading to Drupal 9.
Changes to core themes and theme APIs
-
A new Stable 9 base theme has been added for backwards-compatible markup and assets. Its templates and CSS files have been updated to match with the most recent versions in modules. Drupal 8's Stable theme will still be shipped in Drupal 9 along with Stable 9, but will be deprecated during the Drupal 9 lifecycle to be removed in Drupal 10.
-
Drupal core themes, Bartik, Claro, Seven and Umami no longer depend on Classy or Stable. Now, all these themes set
base theme: false
. All templates and CSS not overridden in these themes will be inherited directly from core. This allows core's internal themes to receive bugfixes directly from module changes in minor releases (rather than developers having to copy the fixes into every theme). (Extending Classy or Stable 9 is still recommended for contributed or custom themes requiring stability between releases.)
Backend (PHP) dependency changes
Symfony
Symfony has been updated from Symfony 3.4.32 to 4.4.9. Like Drupal, Symfony follows a continuous upgrade path and deprecation policy, so that Symfony 4.0 has the same API as 3.4, minus deprecated code. Read about Symfony's Backward Compatibility Promise.
symfony/mime
and symfony/var-dumper
have been updated from 5.0.7 to 5.0.8, and symfony-cmf/routing has been updated from 2.1.1 to 2.3.1.
Twig
Twig has been updated from 1.38.2 to 2.12.5. The changes for PHP developers and template creators are listed at Preparing for use of Twig 2 in Drupal 9.
Composer dependency changes
-
Drupal's Composer dependency requirement has been updated from 1.9.3 to 1.10.0.
-
All backend (Composer) dependencies have received minor- and patch-level updates to the latest versions.
-
The Composer plugins provided by Drupal -- the scaffold plugin, the vendor hardening plugin, and the project message plugin -- are now compatible with Composer 2, and Drupal core now allows either Composer 1 or 2.
-
The
composer/installers
development dependency is no longer pinned to1.9.0
indrupal/core-recommended
. Version 1.9 is now the minimum requirement, andcomposer/installers
may be upgraded whenever a new version is available and a Composer-managed site runscomposer update
.Additionally, Composer has been updated from 1.10.0 to 1.10.5, and
composer/ca-bundle
has been updated from 1.2.6 to 1.2.7. -
The
wikimedia/composer-merge-plugin
dependency has been removed because it is incompatible with Composer 2. It was deprecated in Drupal 8.8.0, and has not been used in core since that release. Any sites that have a separate requirement for this project should add it as a direct dependency.
Doctrine packages
-
SimpleAnnotationReader has been dropped from the master branch of Doctrine Annotations. It consequently has been forked into Drupal core to maintain the same functionality. Contributed modules should not be relying on this library directly.
-
Most Doctrine packages have received minor- and patch-level updates to their latest versions.
doctrine/reflection
1.2.1 has been added as a dependency, replacing our need fodoctrine/common
.doctrine/common
and its dependencies (doctrine/cache
,doctrine/collections
, anddoctrine/inflector
) have been removed as they are no longer used by Drupal core.
Laminas (ZendFramework) dependencies.
Following the project's move, ZendFramework/* packages have been updated to their Laminas equivalents. The packages have also been updated to their latest versions, including a major version update for Diactoros from 1.8.7 to 2.3.0.
Automated testing dependencies
-
Drupal core's testing dependency has been updated to PHPUnit 8.5.3 and support for earlier PHPUnit versions has been removed (since Drupal 9 requires PHP 7.3 or higher).
Changes to backend polyfills
-
The empty
paragonie/random_compat
PHP 5 polyfill has been removed and will no longer be packaged as a dependency of Drupal 9, since Drupal 9 requires PHP 7.3. -
Similarly,
brumann/polyfill-unserialize
(which backported PHP 7 serialization functionality to older versions) has been removed since it is no longer required. -
Finally,
symfony/polyfill-php70
has been removed since PHP 7.0 is not supported by Drupal 9 nor Symfony 4.
Other noteworthy backend dependency changes
-
Wherever possible, backend production and development dependencies have been updated to the latest major, minor, or patch-level versions.
-
Guzzle's minimum version was updated from 6.3 to 6.5.4.
-
The TYPO3 Phar Stream Wrapper has been updated from 2.1.2 to 3.1.4.
-
The package
easyrdf/easyrdf
is no longer a runtime dependency of Drupal and will not be included in tagged releases. Contributed or custom modules using EasyRDF need to add the dependency to theircomposer.json
. -
Drupal is now using stable releases for behat/mink (1.8.0) and behat/mink-selenium2-driver (1.4.0). These were previously pinned to development versions because a critical bug affecting Drupal core had not been resolved in any stable release.
-
Drupal 9 uses Composer's APCu optimised classloader by default. If you were setting
$settings['class_loader_auto_detect'] = FALSE;
in your settings.php to use only Composer's classloader in Drupal 8, this is no longer necessary and can be removed. See https://www.drupal.org/node/3116384 for more information.
Support for using a wincache based classloader is removed from Drupal 9. See https://www.drupal.org/node/3116297 for more information.
Frontend (CSS and JavaScript) dependency changes
jQuery
The jQuery
library was updated from 3.4.1 to 3.5.1, which includes the full, forward-compatible fix for the security issue mitigated by SA-CORE-2020-002. Read more in jQuery's release history.
The jQuery update introduces security fixes that may be disruptive to some modules, themes, or sites that used self-closing HTML tags incorrectly for tags that did not support them (e.g., <div />
instead of <div></div>
). For more information, read the change record on the jQuery 3.5 update.
Drupal 9 will retain a dependency on jQuery 3.x as long as jQuery 3.x is supported (since a stable version of jQuery 4 is not yet available).
jQuery UI
Most jQuery UI components were deprecated in Drupal 8.8 and removed in Drupal 9.0. The libraries are now provided as contributed modules to make updating easier for any modules or themes that depend on them. See the change record on the removal of these jQuery UI libraries for more information.
The libraries that are still in use as of Drupal 8.8 were forked into Drupal 9 core to make it easier to fix any potential security issues with jQuery UI before Drupal 9's end-of-life. We plan to deprecate and remove all of these forked components prior to Drupal 10.0.0's release.
For a simple upgrade path to Drupal 9, see the change record for information on how to use the provided contributed projects that provide replacements for any modules or themes that depend on these deprecated asset libraries.
Since jQuery UI itself is no longer actively supported, it is recommended to find an alternative for the longer term.
Browser polyfills
The following browser support polyfill libraries were deprecated in 8.8.0 and have been removed from Drupal 9.0 because they are no longer required by any of the browsers supported by Drupal core:
-
html5shiv
-
matchMedia
-
domready
(Replaced by a single simple function that will now work in all supported browsers. See domready is deprecated for more information.) -
classList
For sites that need to support older browsers, the contributed html5shiv module and matchmedia module provide identical replacements for the core libraries.
jQuery Cookie replaced by js-cookie
The jquery.cookie has been replaced with js-cookie version 3.0.0-rc.0. The core/js-cookie
library is introduced, and a backwards-compatible shim is provided as core/jquery.cookie
for Drupal 9.
This also required removing jQuery Joyride's dependency on jQuery Cookie. If your site or module initializes Joyride manually, read the change record about the change to Joyride.
Other frontend dependency changes
-
The Normalize.css dependency has been updated from 3.0.3 to 8.0.1. Themes that are not extending Stable or Classy should manually test in case they need to update. Drupal 8's Stable theme will continue using normalize.css 3.0.3 for backwards compatibility. Read the change record on the normalize.css upgrade for more information.
-
The Popper.js library has been updated to version 2.0.6. This migration guide is available for anyone that needs to convert their Popper.js 1.x compatible code to 2.x.
-
Drupal 9 will continue to depend on CKEditor 4, as the CKEditor maintainers have agreed to coordinate CKEditor 4 security fixes with the Drupal project until the end of 2023.
JavaScript development dependency changes
-
Node.js is a development dependency for Drupal core. In Drupal 9, Drupal core's Node.js requirement has been updated from 8.11.0 to 12.0.0. (Information on changes in Node.js 12.) An updated version of Node.js can be installed directly or with nvm. This only affects sites that have installed Drupal core's JavaScript development dependencies with npm or yarn.
A compatibility issue with Babel has also been resolved, and Drupal's JavaScript development tools are forward-compatible with Node.js versions up to 14.
-
The Stylelint development dependency has been updated from 12.0.1 to 13.3.3.
-
All of Drupal's other JavaScript development packages in
packages.json
have been updated to the latest secure versions. This does not affect production sites.
Known issues
Search the issue queue for known issues.
- #3145501: updb error processMultivalueBaseFieldHandler()
- #3135247: Composer's "prefer-stable" setting cannot be relied on to produce a stable release
- #3145563: Route serialization incompatibilities between PHP 7.4 and 7.3 (9.x only)
- Drupal console is not yet compatible with Drupal 9, and if installed will prevent a composer update.
All changes since 9.0.0-rc1
- #3118741 by dww, lauriii, xjm, nod_, tedbow, longwave, catch: [Security] Update yarn dependencies to fix security issues
- by xjm: Revert PHPCS ruleset to 9.0.0-rc1 because enabling rules is not an allowed change during RC.
- #2824935 by idebr, mfernea, Deepak Goyal, pfrenssen, longwave, hgunicamp, jofitz, andypost, daffie: Fix Squiz.ControlStructures.SwitchDeclaration coding standard
- #3107926 by jungle, xjm, lauriii, longwave: Update stylelint to ^13.0.0
- #3109795 by alexpott, Berdir: Entity plural label context is not set as expected
- #3144205 by jungle, alexpott, longwave: Update dependencies for Drupal 9 before release
- #2891603 by eiriksm, alexpott, charlietoleary, Grayle, drclaw, fgm: Contextual links can't handle multiple occurrences of the same contextual links (again)
- #2716115 by LittleCoding, gnuget, jungle, gapple, tatarbj, sandeep_jangra, erlendoos, markcarver, NickDickinsonWilde, cayriawill, catch, geek-merlin: Allow attributes passed with CSS in libraries (SRI)
- #3123095 by quietone, Neslee Canil Pinto, benjifisher, mikelutz, catch: Rollback of complete node migration fails
- #2710407 by bobbygryzynger, dww, Kingdutch, Krzysztof Domański, jp.stacey, johnny5th, tea.time, joachim, andileco, Lendude, xjm, percoction: Option for 'Transform dashes in URL to spaces in term name filter values' on term arguments doesn't affect the query
- #2969231 by quietone, NickDickinsonWilde, joachim, xjm: errors in migration process configuration don't give a clear message
- #3123065 by jungle, daffie: Fix 'Drupal.NamingConventions.ValidClassName' coding standard
- #3025394 by eyilmaz, vsujeetkumar, Kristen Pol, priyanka.sahni, dawehner: MenuActiveTrail should keep its cid (cache id) to avoid wrong cache sets for 403
- #3138774 by sja112, mohrerao, shalinigaur: Fix "DoesNot" relevant typos in core
- #3143085 by neclimdul: Define and optimize alias definition in OptimizedPhpArrayDumper
- #2901745 by kostyashupenko, pazhyn, MerryHamster, ridhimaabrol24, andypost, vacho, longwave, mfernea: Fix 'PSR2.Namespaces.UseDeclaration.UseAfterNamespace' coding standard
- #3123068 by longwave: Fix 'Drupal.Semantics.FunctionT.ConcatString' coding standard
- #2937552 by longwave: Fix 'Drupal.Commenting.DocComment.TagsNotGrouped' coding standard
- #3138793 by sja112, mohrerao: Fix "configuration" relevant typos in core
- #3138801 by sja112, ankit.singh: Fix "readily" relevant typos in core
- #3138787 by mohrerao, sja112: Fix "response" relevant typos in core
- #3138718 by sja112, longwave, dww, xjm, alexpott: Convert British English spellings to American English, for the umpteenth time
- #3138802 by sja112, kkalashnikov: Fix "snafus" relevant typos in core
- #3138803 by sja112: Fix "strength" relevant typos in core
- #3138792 by sja112, dww: Fix "compatibility" relevant typos in core
- #3138799 by sja112, kkalashnikov: Fix "description" relevant typos in core
- #3138786 by sja112, mohrerao: Fix "Protected" relevant typos in core
- #3138785 by sja112, ankit.singh: Fix "Picasso" relevant typos in core
- #3138775 by sja112, mohrerao: Fix "Monoceros" relevant typos in core
- #3143339 by mohrerao, mondrake, longwave: Clean up the arguments of calls to WebAssert::titleEquals() and AssertLegacyTrait::assertTitle()
- #3143115 by Ramya Balasubramanian, mrinalini9, atul4drupal, xjm: README.txt file format for Drupal
- #3139218 by sja112, mondrake, xjm, ketikagrover, daffie: Replace usages of AssertLegacyTrait::assertResponse(), which is deprecated
- #3133798 by Beakerboy, daffie: Semicolon removed from query even when it is allowed
- #3138721 by sja112, dww: Fix "neccessary" typos in core
- #3138789 by sja112, jungle, Maithri Shetty: Fix "blockquote" relevant typos in core
- #3138778 by sja112, jungle: Fix "Nourriture" relevant typos in core
- #3138783 by mohrerao, jungle, DevJoJodae: Fix "Partially" relevant typos in core
- #3138772 by sja112, kkalashnikov, jungle, DevJoJodae: Fix "Disable" relevant typos in core
- #1831560 by acbramley, CRZDEV, mvwensen, fago, David_Rothstein, harsha012, Lendude, mrinalini9, Devin Carlson, borisson_, Gábor Hojtsy: Remove Html::resetSeenIds() call during form processing
- #3002820 by daffie, pavnish, dww, sokru, mmjvb: PHP Warning in template_preprocess_update_report(): Invalid argument supplied for foreach()
- #3139439 by Bunty Badgujar, mondrake, xjm, daffie: Replace usages of deprecated AssertLegacyTrait::assertHeader()
- #3143235 by alexpott, mondrake: Convert ::expectExceptionMessageRegExp to ::expectExceptionMessageMatches
- #3139403 by sja112, mondrake, xjm: Replace usages of deprecated AssertLegacyTrait::assertElement(Not)Present()
- #2766135 by hchonov, jeroen.b, amateescu, neclimdul, gordon, chipway, jmuzz, timmillwood, daffie: EntityQuery with condition on the revision field leads to wrong results
- #3128880 by daffie, alexpott, mondrake: Make ConnectionUnitTest also run for PostgreSQL
- #3134308 by quietone, mrinalini9, benjifisher, xjm: Change 'is was' to 'is' in comments
- #3101214 by mrinalini9, Sutharsan, Kristen Pol: Document that Core is implicitly allowed to scaffold files
- #3055055 by hash6, scott_euser, jhodgdon, amarphule, anmolgoyal74, Gayathri J, jenniferaube, alonaoneill, diqidoq, kishor_kolekar, abhisekmazumdar: Convert appearance-related modules: breakpoint, color, layout_builder, layout_discovery module hook_help() to topic(s)
- #3097651 by kishor_kolekar, sauravk, reinchek, Neslee Canil Pinto, Adam Szalapski, sibustephen, ravi.shankar, kostyashupenko, Krzysztof Domański, KondratievaS, lauriii, ckrina: Implement secondary tabs based on the designs
- #2974640 by ilya.no, Berdir: ExposedFormPluginBase::exposedFormAlter() sets a bogus weight key
- #3071682 by Sam152, Roensby, phenaproxima, Wim Leers: The oembed Resource value object should be more permissive for NULL dimensions
- #3044059 by jhodgdon, vadim.hirbu, Gayathri J, Vitor Faria, sukottokun, ChrisBee, BramDriesen, rkoller: Convert big_pipe, dynamic_page_cache, page_cache module hook_help() to topic(s)
- #3047806 by jhodgdon, Gayathri J, thejimbirch, anmolgoyal74, luwoldy, batigolix, shimpy, alonaoneill, volkswagenchick, tatarbj, Amber Himes Matz, rkoller, CelSki, xjm: Convert book.module hook_help() to topic(s)
- #3101210 by mrinalini9, Sutharsan, Kristen Pol, greg.1.anderson: Remove 'overwrite' as documented example in scaffold options
- #3136389 by jyotimishra123, Hardik_Patel_12, Suresh Prabhu Parkala, shimpy, longwave, quietone: Remove '@group legacy' from tests that do not exercise deprecated code