Cookies ahead

Our support chat tool "Intercom" would like to collect some more data on you. See the related link for more details.

Docs

Craft CMS performance tips

Reviewedbyfl

Markdown ↓

Identify and fix Craft CMS performance issues, from database queries to caching strategies, for faster page loads on fortrabbit.

Get ready

Please check out our general PHP performance section article as well before looking at specific Craft CMS related performance issues.

The amount and complexity of database queries, as well as the size of your dataset, have a direct impact on the performance of your site. While the queries you create in your templates are more or less your responsibility, there are other queries that you can't directly control. We have analyzed hundreds of Craft sites to understand common query patterns. Especially sites with large amounts of data (Entries, Fields, etc) and frequent content updates suffer from these "hidden" queries.

How Craft CMS makes use of the database

Craft CMS abstracts database queries through Twig, eliminating the need to write raw MySQL; however, this abstraction can mask performance issues if misused. You can query the database directly from templates without writing SQL, but this convenience introduces several common pitfalls.

  • Craft is running database queries all the time, completely blocking
  • Craft is joining all the time, since everything is an element, that can get slow quickly

There is much more to know, exceeding the scope of this post. Here are the most important parts:

How the MySQL dataset size matters

The flexible content model in Craft CMS makes it easy to write code that makes either too many database queries and/or slow queries in MySQL. Most commonly poorly performing MySQL queries are easy to miss during development, since with local development you commonly only have a small dummy dataset.

Also mind your local machine has a different hardware than your hosted website. In production later on, when all the pages are published and a couple of blog posts have been written, the underlying issues will become more visible. MySQL query runtime is not just adding up, it's multiplying.

General tips on MySQL performance with Craft CMS

Prevention is better than cure! If you're reading this, the odds are you may already have run into performance issues on a Craft CMS project. But if you're just starting out with a new project, being aware of how Craft models content behind the scenes can spare you a lot of time-consuming debugging later on.

Look out for code smell: Common Craft performance anti-patterns include:

  • where conditions on custom fields
  • Queries in nested loops (N+1)
  • Order on custom fields orderBy

Optimizing database queries

Database indexes

Use the Craft Debug Toolbar

Craft CMS integrates the Yii debug toolbar, which shows query counts and execution times (see nystudio107 profiling guide). A good rule of thumb: if you run more than 50 queries per page, optimize your approach. It's simple to use and helps identify slow queries during development.

Use the Relax plugin

Fortunately, there is a plugin called Relax that takes care it. We have released it for free to help our clients and the broader craft community.

Like described above, a PHP process is busy as long as it is executing. No one will pick up the phone (return a web page) when all the PHP processes are busy. There are various reasons why PHP requests are busy or are running for too long.

Examples from support:

  • A plugin is querying an external service in a blocking way and the answer is taking too long
  • The database is overwhelmed by too many or too expensive queries

Insufficient memory or CPU capacity prevents calculations from completing, often surfacing during image transformations or high concurrent load. This typically occurs when the app tries to do too much at once.

Examples from our support:

  • Image transformations are used extensively to create too many versions of a certain image in too many sizes and formats
  • Thousands of queue messages need to be processed, often caused by bulk-updates
  • Bots crawl the entire site including non-existing pages which are not cacheable

Craft has its own queue implementation that you can monitor and manage from the Control Panel (see Craft CMS queueing guide). The craft-async-queue plugin improves queue performance by offloading processing. Hanging queues indicate a problem.

To see if performance problems are related to the Craft queue, check if one is running and delete it from the Craft Control Panel. This of course is only possible when the website is still responding.

Look for errors in the Craft queue.

Excessive disk operations slow websites when file system access becomes frequent and unoptimized. This typically stems from caching issues or verbose logging.

Examples from support:

  • Using Craft's Twig {% cache %} tag missing the key attribute can lead to thousands of cache files with the same data and a terrible cache-hit-rate
  • The website is configured to write verbose log files

Static files in /templates

Storing static assets (CSS, JavaScript) in the /templates folder forces Craft to execute PHP when serving them, adding unnecessary overhead. Always place static files in /web/ or a subdirectory to avoid PHP processing and serve them directly.

Twig cache tag

Use Craft's {% cache %} tag with a specific key to cache expensive query results, but avoid generic keys that create thousands of cache items and waste disk space. Misconfigured caching hurts performance more than it helps.

Performance problems are also often caused by general misconfiguration. Examples from support:

  • Not having set the environment to production - this can contribute to bad performance since in development mode more things are getting logged
  • A plugin is (mis)configured to blow up the database

Fixing and mitigation

In our experience, problems are often unique to individual projects. So there is no silver bullet to make things fast. There are however some general things you can do:

Check and maybe block certain requests

Depending on your configuration, checking the source of requests might help you to understand where resources are getting spent.

Examples from support:

  • A deep content structure, creating an endless amount of possible pages that are getting crawled by web crawlers. Block certain bots or rethink your content structure.
  • Common bot attacks targeting WordPress requesting a wp-login page which results in a 404 page, but that page is not cached or creating an expensive database query, so that the requests are generating a lot of load.
  • The Blitz plugin is configured to flush the cache every hour, which triggers cache warming. See this Twitter thread.

Caching to the rescue

Caching can be highly beneficial, particularly in providing the fastest possible end user experience but shouldn't be a crutch. Instead, it's usually better to find and remediate the root cause of the issue where possible.

Doing caching wrong can also be the problem itself.

You want repeating parts of the website or full pages to be cached and rendered without hitting PHP or a database query touching the server. A "mega menu" is a perfect example and an opportunity for fragment caching. It creates the same database queries (sometimes 50+) for every page.

There are multiple approaches for caching in Craft CMS including:

  • Native Twig cache tag - the out of the box tool for fragment caching, be careful when using for side effects, more above.
  • Blitz Craft CMS plugin - a popular full cache plugin with tons of options
  • Upper Craft CMS plugin (by fortrabbit co-founder Oliver Stark) - integrates reverse proxies (Cloudflare, Vanish, KeyCDN) with Craft

Please be careful about caching. In our experience, this is probably causing more problems than it is solving.

Further reading

Ryan has some good educational video content (some paid, some free) on related topics:

Written by a human. Review, grammar checks and typo fixes by AI.

AI use & editorial processEdit on GitHub ↗