Developer Drupal

What's new in Drupal 11.4: an overview of changes vs 11.3

Drupal 11.4 is the next minor release in the 11.x branch, with a stable launch planned for the week starting June 22, 2026. It doesn’t break backward compatibility for public APIs, but it brings plenty of concrete improvements: PHP attribute routing, a new bootstrap based on Symfony Runtime, Brotli compression for assets, SEO-oriented robots.txt changes, and a whole list of deprecations worth handling in custom modules. The 11.4.0-beta1 release is already available (since June 3, 2026), so every change described below is already in the code and you can test it right now (beta is not recommended for production, though). Below I walk through what actually changes compared to Drupal 11.3.

In this article:

When Drupal 11.4 is released and how long it will be supported

Drupal 11.4.0-beta1 was published on June 3, 2026, and the stable 11.4.0 release is scheduled for the week starting June 22, 2026 (per the official schedule updated on June 4, 2026; beta1 slipped, so the whole cycle shifted). This is a minor release, which under Drupal’s policy means it adds new features and improvements but doesn’t break backward compatibility for public APIs. Internal APIs and experimental modules may change, though, so contributed and custom modules may need updating.

The support dates matter. The 11.4.x branch will receive security support until June 2027, and 11.3.x until December 2026. The release of 11.4 also marks the end of security support for 11.2.x and 10.5.x. The entire Drupal 11 line will be supported until the release of Drupal 13.

In practice: if you’re on 11.3, you have until December 2026, but moving to 11.4 extends your security window by six months and is relatively cheap, because it’s a minor release without BC breaks. If you’re just getting to know this line, we covered the features and goals of Drupal 11 in a separate article.

PHP attribute routing, the biggest news for developers

The most interesting developer change in 11.4 is the ability to define routes directly in code using PHP attributes, instead of only in *.routing.yml files. Every class in a module’s Controller namespace (e.g. Drupal\example\Controller) that has the Symfony\Component\Routing\Attribute\Route attribute will be picked up as a route definition.

The #[Route] attribute can be applied at the method level and at the class level, where it sets shared defaults. The defaults, requirements, and options keys are merged (the method level takes precedence), while name and path are concatenated, so you can set a prefix at the class level and suffixes on methods. Routes based on the __invoke method are supported too.

Importantly, the mechanism was extended to forms as well. Classes implementing Drupal\Core\Form\FormInterface in a module’s Form namespace, annotated with the Route attribute at the class level, will also be picked up as route definitions. The attribute must be on the class; attributes on a form’s methods are ignored. Entity form routes should still be defined via the route provider in the entity type definition.

This solution supplements, rather than replaces, declarations in *.routing.yml. For teams writing a lot of custom code, it means less jumping between YAML files and PHP classes, and keeping route definitions closer to the controller logic.

Symfony Runtime and the new bootstrap

Drupal 11.4 adopts the symfony/runtime component to simplify and separate the bootstrap process. For most sites this is an invisible change, but if you have a custom front controller (a custom index.php or another entry script), it’s worth reading the dedicated change record, because the way the application is initialized changes.

The good news: existing front controllers will keep working at least until Drupal 12, so there’s no pressure to rewrite anything immediately. It’s more of a signal of where the bootstrap architecture is heading.

In addition, symfony/polyfill-php86 was added, so some functions introduced in PHP 8.6 are available in Drupal 11.4 regardless of the PHP version on your server.

Performance: Brotli, faster recipes, and a new cache

Performance is one of the stronger areas of this release.

  • Brotli compression for CSS and JS. Drupal now generates .br (Brotli) versions of aggregated CSS and JS files if the server has the ext-brotli PHP extension. It works alongside the existing gzip, and Brotli typically delivers 15-25% better compression, meaning smaller files and faster loads. The configuration was also unified: the system.performance.css.gzip and js.gzip settings were replaced with css.compress and js.compress, and a post-update hook (system_post_update_migrate_compress_setting()) migrates the old settings automatically. Apache sites work out of the box (the updated .htaccess serves .br with a gzip fallback); on Nginx you need to manually add a configuration with the brotli_static directive (requires the ngx_brotli module).
  • Faster recipe system. The recipe system’s performance was improved by installing extensions in batches. Developers should use RecipeRunner::installModules(), which leverages multi-module processing.
  • New cache.file_parsing cache bin. A dedicated bin for persistent caching of file parsing results was added (along with FileParsingCacheCollectorBase and YamlCacheCollector, used for example for libraries.yml and routing.yaml). Unlike the existing APCu-based FileCache, this cache survives cache clears and is consistent between CLI and multiple web servers, which improves response times both locally (frequent cache clears via the CLI) and on production right after a deployment.
  • Font preloading. Library definitions (and overrides in SDC components) now support a fonts key for preloading fonts. Previously there was no official API for this, and you had to add the links to the HTML header manually.

These changes are nice in that they largely work automatically after the upgrade. It’s a classic example of how keeping Drupal up to date simply pays off in performance.

Changes for site builders and editors

Not everything in 11.4 happens in code. A few changes will also be felt by the people building and editing pages.

  • New “Manage display” overview page. At /admin/structure/types/manage/{bundle}/display there’s a new page that the “Manage display” tab now defaults to. Instead of immediately opening the default view mode edit form, it shows a list of all display modes with their label, description, and enabled/disabled status, which you can toggle right from this view. The page is independent of any specific builder, which makes it easier to integrate Layout Builder, Drupal Canvas, and other tools. If your module has functional tests assuming the old routing behavior, you’ll need to update them.
  • New permission to view unpublished blocks. A “view unpublished block content” permission was added, letting you grant users the right to view unpublished block content entities.
  • Node search as a separate sub-module. The node_search plugin was moved to a new search_node sub-module within the Search module. If you have a custom plugin extending \Drupal\node\Plugin\Search\NodeSearch, switch to \Drupal\search_node\Plugin\Search\SearchNode.

SEO and security

Drupal 11.4 improves several default settings that affect search engine visibility and resilience to invalid data.

  • robots.txt blocks search result pages. The default robots.txt now blocks indexing of search result pages with query parameters. The rules Disallow: /search? and Disallow: /index.php/search? were added. The reason: search engines were indexing dynamic results and crawling infinite combinations of faceted search pages, which strained the server and degraded SEO quality. If you have a custom, modified robots.txt, you have to add these rules manually.
  • UUID validation. The uuid field type, used automatically to store content entity UUIDs, now checks that the value is in fact a valid UUID.
  • Cacheable 404 responses. Router::matchRequest() now throws CacheableResourceNotFoundException instead of the plain ResourceNotFoundException, and a new cache context for the exception status was added. In practice this means better caching of 404 and 403 responses.

Front-end, Twig, and CKEditor

The presentation layer and decoupled projects get a few improvements too.

  • Functions from twig/html-extra. The twig/html-extra package was added, exposing the html_cva, html_attr, and html_classes functions. All three are now available in Twig templates, which simplifies building attributes and CSS classes.
  • CKEditor 5 updated to 47.6.2. The editor received a version update along with numerous smaller front-end dependency updates.
  • #url in responsive image is now a Url object. In the responsive_image_formatter theme element, the #url property is now a Drupal\Core\Url object instead of a string, which allows manipulating URL options.
  • New resolvable_uri property on the link field. The link field gained a resolvable_uri property that returns a link ready to use in an href attribute. This matters for decoupled and JSON:API projects: instead of a raw internal:/ with a separate fragment, the API returns a ready /#main-content right away. A [entity:field_link:resolvable_uri] token was also added, and setting resolvable_uri initializes the remaining link properties (uri, query, fragment).

What you need to know before upgrading

A few things worth checking before you upgrade production.

Read also: a step-by-step Drupal upgrade, preparation and common challenges.

  • The drupal/legacy-project template is marked as abandoned. If your project still relies on drupal/legacy-project, it’s time to switch to drupal/recommended-project.
  • The path to Drupal 12. Sites must be on at least 11.3.0 before upgrading to 12.x, because Drupal 12 removed update hooks predating 11.3. Moving to 11.4 puts you in a good position for that migration.
  • HTML5 validation. An enable_html5_validation setting was added to settings.php. In Drupal 12 HTML5 validation will be disabled by default, so it’s worth consciously setting this value for your forms now.
  • Nginx and Brotli. If you host on Nginx and want to use Brotli pre-compression, add a server configuration with brotli_static (Apache requires no changes). Also check any code that sets css.gzip/js.gzip programmatically, and switch to css.compress/js.compress.
  • Custom search plugins. If you have a plugin based on NodeSearch, update it for the new search_node sub-module.

The most important deprecations in 11.4

In this release, quite a few API elements were marked as deprecated. If you maintain your own modules, it’s worth planning a review. The most important ones:

  • check_markup() is deprecated, with no replacement. The recommendation: return a renderable array instead of flattening to markup, to preserve cacheability metadata.
  • The render functions hide() and show() are deprecated. Use the #printed flag in the render array instead.
  • file_get_file_references() is replaced by the FileReferenceResolver service.
  • node_access_rebuild() and node_access_grants are replaced by services (including NodeGrantsHelper).
  • \Drupal\node\Controller\NodeViewController is replaced by EntityViewController.
  • The user.pass.http, user.login.http, user.login_status.http, and user.logout.http routes were moved to the rest module.
  • Accessing the global autoload variable is deprecated; include vendor/autoload.php instead.
  • A number of locale functions (locale.batch.inc, locale.bulk.inc, locale.compare.inc) are replaced by new services, including LocaleSource, LocaleFileManager, and LocaleFetch.

All deprecations have replacements described in the change records on drupal.org, and the code itself doesn’t stop working in 11.4. Removal won’t happen until the next major.

Is it worth upgrading to 11.4?

If you’re on 11.3, upgrading to 11.4 is a low-risk move: a minor release, no BC breaks for public APIs, and in return you get longer security support (until June 2027), real performance improvements (Brotli, faster recipes, the new cache), better default SEO, and more convenient routing for developers.

The most attention is needed for custom code: review the deprecations, check any custom front controller against Symfony Runtime, and add the rules to a modified robots.txt. For a typical site built on standard modules, the upgrade should be quick, and the benefits noticeable right after deployment. We described what a well-prepared Drupal upgrade looks like in practice in a separate guide.

Need help upgrading or maintaining Drupal?

At Droptica we’ve worked with Drupal for over a decade: we upgrade, maintain, and develop enterprise platforms, intranets, and complex web applications. We know how to run a minor upgrade without downtime and how to handle deprecations in custom code so your project is ready for Drupal 12 as well.

If you’re planning an upgrade to Drupal 11.4 or want to make sure your project is secure and performant, check out our Drupal development services or contact us directly to discuss the details.