Drupal 8 reached its end of life in November 2021, while the support of Drupal 7 is extended till January 2025. It's totally stable, feature-rich, actively maintained, and has tons of available modules for a functionality extension, and these modules are very stable as well. In this article, I would like to draw your attention to Drupal 7 performance. You can find a lot of information on Drupal 7 performance optimization on the Internet since the version has been available for a long time, but anyway, things change, and new options appear. I'd like to highlight these options.
Drupal performance is very important because it can lead to higher conversion rates, higher search ranking, and hosting costs reduction. In this article, we'll look at the different ways of improving the performance of a Drupal 7 site. I'll focus on the performance of the server side, but there are other areas where website performance can and should be improved including the front end, database, etc. Some improvements are easier to implement than others, though.
Let's start with the easiest settings to set.
This is the only exception in this article since it concerns Drupal front-end performance, i.e. page load improvements after a response is delivered to a browser. People sometimes complain that Drupal is slow, but I saw many sites that hadn't had JS or CSS aggregation enabled. Those are just two checkboxes in the settings which noticeably decrease the number of files to load. This setting is very easy to fix, so don't neglect it.
When it comes to back-end tips, you'd better use relevant software releases. It's recommended to use PHP 8.0 or higher versions. All versions of PHP from 5.3 to 7.4 are EOL, but still supported by Drupal until August 1st 2023. Please note that PHP 8.0 is EOL too, but receives security fixes until November 26th 2023. Also, PHP is shipped with a Zend OPcache bytecode engine starting from version 5.5, and that noticeably improves PHP code execution performance.
PHP 8.1 is significantly faster and less memory-consuming in comparison with PHP 8.0 and officially supported since Drupal 7.92: that means there are no known issues with PHP 8.1 in Drupal core. Popular contrib modules also work with PHP 8 very well and there is a very low probability that the contrib project you want to utilize doesn't support PHP 8.1, and maybe you'll need to adapt custom code.
Also, decide if you need HTTP/2 or not. It can noticeably improve a page load time, but it’s supported by browsers over TLS only and makes HTTP 1.1 specific optimizations like image sprites, domain sharding, etc. at least useless, and makes some of them affect performance badly.
We agreed that the recent software is a must. The same applies to the latest Drupal updates.
Drupal core and modules
New Drupal and contrib project releases can contain not only bug fixes, new features, and security fixes (please update as soon as possible in this case) but also performance improvements, so you should use the latest available versions and update regularly.
Usually, a site runs in different environments: local and development for development purposes, staging for testing purposes (before moving updates to production), and production, but there may be more environments. And it's very natural that they have different settings and lists of enabled and disabled modules. For example, the local and development environments usually have some development-helper modules enabled like Devel, disabled caching, CSS/JS aggregation, and many others. In the production environment, you definitely should not have development-helper modules enabled, but there'll be some other, for example, Google Analytics, which you'll probably have enabled on the production only.
So, don't forget to disable the modules that you don't use to avoid loading needless code which takes an additional time. If any module is not used in all environments (for example, it was added during development just for an experiment) then remove it from a source, but first, don't forget to uninstall it properly because missing (improperly removed) modules may lead to Drupal performance issues.
Drupal core caching
Drupal core provides options to cache blocks (which should be enabled if possible) and also to cache whole pages for anonymous users which are very useful for content sites on which most regular users are anonymous.
Drupal is used with many contrib modules, and it's important for them to utilize caching and provide their own caching, related configuration possibilities, and related configuration.
Views is the most popular Drupal contrib module and many website outputs are built with the help of it. Views retrieve results from data storage, and in case of a complex condition, sorting, or applied aggregation options it may become heavy in terms of performance. In the case of a complex output with a lot of fields, it may be heavy as well.
Views provide a time-based (with a specified cache lifetime) cache and both the raw query result and the resulting output can be cached.
Since Views is mostly used to display regular content (nodes) of the particular type(s), the views cache can be flushed/rebuilt only when the corresponding content is updated. This results in better cache utilization in comparison with time-based caching. And the Views content cache contrib module provides a caching mechanism for Views that works in this way. In case updates on the site happen not frequently (for example, a blog with a few new posts per week) cache may live for days and even weeks and reflect content updates immediately in comparison with the time-based cache where the lifetime is usually limited to a few hours at the maximum.
A page cache for anonymous users provided by the Drupal core requires a partial bootstrap to deliver the cache from Drupal. When it’s possible Varnish is a better option to cache pages for anonymous users, it delivers the cache to users without even triggering Drupal. In advanced usage, Varnish can be utilized to cache content for logged-in users as well.
You'll need the Varnish module for integration, and the Cache Expiration and the Purge additional modules are recommended for cache expiration and cleaning. Please see the module's documentation for configuration details.
Varnish integration with Drupal may differ depending on hosting actually. For example, on Acquia you will not need the Varnish module, it just will not work. Note configuration code example:
$conf['cache_backends'] = 'includes/cache-install.inc'; $conf['cache_backends'] = './sites/all/modules/memcache/memcache.inc'; $conf['cache_default_class'] = 'MemCacheDrupal'; $conf['cache_class_cache_form'] = 'DrupalDatabaseCache'; $conf['cache_class_cache_page'] = 'DrupalFakeCache';
Page cache handler is set to the DrupalFakeCache class, so Drupal returns proper cache control headers, but a response is cached only once by Varnish and not cached by Drupal itself. Please check your hosting documentation first to configure Varnish properly.
When Varnish is not available, there is one more simple option to cache whole pages for anonymous users for better performance: the Boost module which caches pages to regular .html files and delivers just these static files as a cache when possible. Please see the module's README.txt for more info on installation and configuration. Again, Cache Expiration and Purge are recommended as additions.
Entities are a crucial part of Drupal, and they are very handy to deal with different kinds of data. In Drupal core nodes, comments, users, taxonomy terms, taxonomy vocabularies, and files are the entities. Many other types of entities are defined by contrib modules, and the entities defined by custom code are very useful as well.
Fieldable entities, especially when there are many fields attached, may be too heavy to load fast. When entities are frequently loaded on a website, for example, because of some processing as a reaction to some users' actions, it's better to cache the entities. Drupal caches the entities via the core's field cache by default, but the Entity cache module provides a more efficient solution for boosting Drupal entity cache performance. But it's highly recommended to use it with Memcached or Redis as cache storage to achieve maximum performance improvements.
Drupal provides search functionality from its core and stores a search index in a database, and maybe not be performant enough when there is a lot of content on a website. The Apache Solr Search module extends Drupal core search functionality to allow using an Apache Solr search platform instead of the database for better performance and scalability. It also adds some new features to Drupal search functionality.
One more solution to build search functionality in Drupal is the Search API module. Search results and filters are usually output via Views when the module is used, and this adds more flexibility. Search API separates "search index" and "search server" terms and implements a pluggable system for search backends so there are many options available: Solr, Sphinx, Database, and others.
You should never implement the full-text search functionality by building the output via the Views module and querying results from the database using "contains" conditions.
Drupal performs different tasks on cron, including a cleanup, particular tasks are implemented via a hook_cron() hook. Basically, there is no need to execute all of these tasks at the same time (which is the default behavior), especially when you need to execute some of the tasks very frequently, for example, a scheduled content publication, subscriptions' expiration, or queue processing. In such cases, cron tasks running simultaneously may cause performance issues and a frequent execution of tasks that shouldn't be done that often: all of these may slow down other tasks execution which really need to run frequently.
Entities without revisions
When you have the process on a site that creates or updates many entities, for example, nodes, and you need to speed up this process, for instance, because a user awaits the result of this process, the Field SQL norevisions module may be helpful in case created/updated entities do not use revisioning. This module halves the amount of executed database queries needed to insert/update entities' field values. Please read the Fields with no revisions article for more information on the problem and solution.
When you deal with entities in code, use entity_load() and node_load_multiple() to load several entities and particularly nodes instead of entity_load_single() (provided by the Entity API module) and node_load() in loops.
Utilizing cache in code
Use drupal_static() to cache data that is frequently used during a single page request. Use a more advanced technique via $drupal_static_fast covered on the same documentation page for the cases when data is requested a lot of times (hundreds and more) during one process.
This article covers several tips on how to improve Drupal site performance on the server side, but it's not a complete list, of course. There are many other options, some of them applicable to specific needs. Drupal performance can be greatly improved, and there are a lot of options for improvements, many of them are easy to implement and require additional module installation and configuration only, with no other effort.