Blog/ Drupal Performance Optimization Checklist

You must have read plenty of articles on how to tweak your Drupal site to improve its page load times. This post assembles an exhaustive list of all the configuration changes you can do that help in Drupal performance tuning.

Caching

Enable block cache. Blocks that don't change from one user to another can be cached and served.

Enable Drupal cache for anonymous users. Use this if you are not using any other caching solution such as front-end cache (Varnish) or Boost.

Cache views. There are plenty of options:Use this patch if you want to cache filtered results based on exposed filter selections as well.

Time-based (built into core). Use this if you want to expire the Views cache after a specific period of time and if you are fine serving stale content for some period of time.

Content cache. Use this if you want to expire the Views every time a content is inserted, updated or deleted. Use this if you expect content changes to happen rather infrequently on your site.

Row cache. This caches the rendered output of each row separately but the query is not cached. Row results from the query are converted into a hash to store the rendered output of each row. If the row result changes, then the result is rendered again otherwise it is fetched from cache. Use this if you expect content changes to happen frequently on your site.

Cache panels. There are plenty of options:

Content cache. Use this if you want to expire the Panel cache whenever content is inserted, updated or deleted. Use this if you expect content changes to happen rather infrequently on your site.

Page cache. Use this if you want to cache panel based on Drupal path and URL.

Hash cache. Use this if you want panel to be cached with more granularity than just Drupal path and URL. This module allows you to create a custom hash for the cache based on contexts, arguments, Drupal path, URL, users and roles. Cache is expired automatically whenever any element of the hash changes.

Install distributed cache that can store cache tables of the database in memory or file. Drupal creates and uses its own cache. By default, it is stored in database in tables whose names start with "cache_". A distributed cache can instead store these caches in memory or file. The popular ones are:I prefer memcache since it's easy to install and configure. A lot of developers prefer Redis. I believe it's a tie between memcache and Redis. File Cache will be the slowest of the three so don't go with that.

Enable Far Future Expiration for static assets. See the Webserver section of this article below for more details.

Install a front-end cache. It stores the HTML response in memory. The next time, the same page is requested, it returns the HTML from memory. As a result, on the second request, web server and PHP are completely bypassed and the page load time is much faster. There are two good open-source front-end caches: Varnish and Squid. Drupal has much better support for Varnish such as expiring particular URLs using Rules. That's why I prefer Varnish.

Use Imageinfo Cache module to pre-generate image styles before they are requested for the first time. By default, Drupal generates image styles only on the first request. Using this module will ensure that the image style has already been created beofre the first request and even the first request is fast. In general, this module won't decrease your page load time much so use this only if you really really need 5 ms of reduction in page load time.

Optimize images and reduce their size. There are multiple ways to do this:

Use Views Litepager module to eliminate COUNT queries from Views. InnoDB tables in MySQL do not store total count and hence a count query requires the engine to actually count the number of rows and that can slow down the query.

Use Picture module for rendering responsive images. This ensures that on small screens, smaller images are downloaded which saves bandwidth and decreases page load time.

Miscellaneous

Disable and uninstall modules that are not required for your application such as Update Manager and Statistics.

On production, disable and uninstall modules that only provide UI functionality. Most common ones are Views UI and Rules UI.

Rewrite your custom modules so that only the hooks are present in .module file. All the other functions should be in other files. Include these files as needed using module_load_include() and form_load_include() functions.

Disable PHP Filter. It uses eval() function to run the code and that is slower than code that is compiled.

Reduce the number of times that cron is run. By default, cron flushes Drupal's cache and as a result, frequent cron runs will trigger frequent cache flushes.

Advanced methods

Cache pages for authenticated users. Front-end caches generally cache pages for anonymous users. If your site is being used mostly by authenticated users, choose one of the following two options:

Cache pages using front-end cache such as Varnish after removing all the cookies. All blocks that have user-specific or page-specific content are loaded using AJAX via AJAX Blocks module. The advantage of this approach is that webserver and PHP are not called when returning base HTML to the browser and as a result page load time decreases dramatically.

Cache pages for authenticated users using Authcache. Use authcache if most blocks in your pages has user-specific or role-specific content. Although this is an excellent module and it works very well, it requires some configuration and maintenance. Also since it uses webserver and PHP, page times are slower than using a front-end cache such as Varnish.

Speed up DNS requests. When you type a website URL in the browser, browser first contacts a DNS service to find the IP address. Typically this request takes anywhere from 50 ms to 200 ms. You can use DNS Anycast network to reduce this time. Some services that can help with this are: AWS Route 53, easyDNS, DNS Made Easy, Akamai, Dyn and Neustar UltraDNS.

Use CDNs for serving dynamic content such as your complete HTML page. With this, you get the above two benefits even for your normal pages and not just for static assets. This requires a lot of configuration and we'll post another article on this soon.

Inline critical CSS/JS. Browsers need to send multiple requests to the server before it can start rendering a page. Once it receives the HTML from the browser, it needs to request all the CSS and JS files present in the header. These are blocking requests and the page won't start rendering till they are received. By inlining the CSS/JS that you need to render the content that is above the fold, browsers don't need to make any more request to start rendering and hence the user perceives the page load times to be faster. This is a tool that is extremely useful for mobile devices since their bandwidth is generally limited and hence easy response takes a long time to arrive. There are multiple ways to do this:

Database

Enable and configure MySQL query cache. It stores the results of past queries in memory. Next time the same query comes, it first sees if the results are already in memory. If yes, it returns the results from memory. If not, the query is passed to the MySQL query engine to fetch the results. MySQL query cache is always up-to-date, i.e. if any of the tables on which the query depends is modified, then the cache is cleared automatically. As a result, there is no need to clear MySQL query cache manually.

I prefer using nginx since its event-driven model makes it much faster and more memory-efficient than Apache.

PHP

Install PHP Opcode Cache. PHP is an interpreted language and it compiles during run-time. Compiler compiles it in two passes. In the first pass, PHP code is converted to an intermediate code (Opcode) which is platform-independent. In the next pass, this code gets converted to binary. Opcode caches store the intermediate code (Opode) in memory so that the next time code runs, compiler can fetch it from memory and skip the first pass. There are plenty of open-source Opcode caches available. Following are the popular ones. I prefer APC because it's easy to install and configure. Starting with PHP 5.5, PHP comes with Zend Optimizer by default so there won't be any need to install Opcode cache separately.

Comments

Great info! Just would like to add this module to the list. I love JCH Optimize is great module for optimizing Drupal website speed. It's a one stop optimization module so it basically does almost all performance optimization reducing need of too many plugins.

Thanks for your suggestion! It's still in sandbox with absolutely no information on its project page so it's impossible to say what it does. That said, I have cloned the module in my local machine and will check it out. If it works well, I'll include it in this list.

Thank you for the amazing guide. Many of these modules were new to me and thanks to your work, I am close to having an incredibly fast intranet portal. I recommend adding Panels Hash Cache (https://www.drupal.org/project/panels_hash_cache) to the list as well, since it is a great alternative to Authcache's Panels/Pane caching and has even more configurations available. Thanks again!

Varnish is really great with Drupal as well. I have been using Varnish, Apache, Nginx and Memcached on my Drupal, because it is support by Cloudways, the managed hosting I am using. The first time I checked my benchmarks I was amazed. The response time was amazing compared to when I was using LAMP stack.

Thanks! Well-done caching allows to speed up the site and get Google Page Speed Insight Score. We used this article optimizing even webdev company site https://www.iflexion.com It's working! 96% of Google score!