We did the professional thing and went back to the drawing board on some ideas, and evaluated every little thing we did to try to see what we missed.

This article shares some of the more frequent problems many EE sites will face, and they’re all really simple fixes. Some of the problems with the particular site were so unique to circumstance we won’t muddy the water with them here.

We won’t link to how to enable these techniques because they vary from version to version and the official ExpressionEngine user guide will be a better resource for this.

If you need a hand with ExpressionEngine optimisation, we're here to help. Get in touch.

Syncing Sucks

Most EE developers turn on file syncing to aid their development workflow. It allows them to use their preferred code editor and version control changes to the template. It’s an all round good idea.

The disadvantage is that it will load the file in each time leading to increased disk I/O activity. As Derek Jones in the comments pointed out, there is one quick check, "Does this template file exist" and then a full read, "...give me it then". Perhaps servers with SSD would actually benefit from reading from files rather than just querying the database.

A quick win with almost all ExpressionEngine sites is to turn file template syncing off on your production environment. A small boost, but one that adds up with each page view.

Additionally add-ons such as SnippetsSync from Bjorn Borresen also allow you to use files to create snippets and global variables. This is great from a workflow perspective, but what I didn’t realise is that for every page load SnippetSync will, well, sync the snippets. This is not surprisingly quite intensive.

Within the plugin’s folder there is a config file in which you can turn snippetssync_production_mode to TRUE. Once that’s set it will stop automatically trying to sync (you can do so manually in the control panel).

On one of our pages, setting it to TRUE removed 42 database calls. Snappy.

But here’s the thing… for the time it was syncing each time it managed to duplicate the same template in ExpressionEngine’s database numerous times. There was about 10 {sn_header} snippets in the system.

While snippets are more lightweight than embeds, they are loaded on every page… whether you are using it on that page or not. The problem here is that it was loading the same snippet numerous times because of syncing duplication. Removing these halved the memory usage of a single page.

Cache the Templates or Cache The Tags

Now that templates aren’t syncing, can we cache them?

Yes... if your site is “read only” you can comfortably take advantage of ExpressionEngine’s built in template caching.

Template caching is quite smart. It will cache as much of a processed version of the page (with the correct entries loaded) as possible.

But if you have contextually dynamic content (for example a login section, different content depending on location or membership group) it doesn’t really work - if you did you might deliver a version of a page intended for User A to User X. Dodgy.

With template caching you define the length of the cache before it clears itself. But if you update, add or delete an entry the appropriate caches will clear themselves. It’s quite smart.

In those instances you can take advantage of the next best thing - tag caching. Tag caching works in a similar basis but you apply it on tags rather than entire templates. For example on the end of a channel entry loop you could add the tag `cache="yes" refresh=“60”` for ExpressionEngine to cache that tag for one hour. This should play nicely with most tags.

If you are able to use Template Caching, don’t worry about tag caching - Template Caching automatically caches tags too.

As of 2.8 ExpressionEngine’s caching can now use Redis or Memcached which provide a further boost if your server allows for it.

Cache the Queries

Not sick of caching yet? You may also be able to employ “Dynamic Channel Query Caching” in ExpressionEngine.

Channel Query Caching remembers the SQL statement that ExpressionEngine ran to get the right data to make things faster next time.

It may seem like quite a small thing, but Channel Entry Loops are actually quite complex in how they query the database: they include many joins and fields each time they’re called. Caching what statement to query the database eases some of the load.

The caveat of using this is that if the site relies on future or expired entries it can’t be trusted; the statement it stores may skip entries that are now meant to show and keep showing entries that have long gone.

Disable all the Things

Talking about SQL joins… what are they doing? They’re linking disparate tables from the database together so you can use the simple channel entry loop.

In the database, the field data and the entry names are stored in completely different tables. When you then factor in member data and categories as well, the number of joins required in the SQL statement to make your simple channel entry loop work is scary. It starts to become SQL Soup.

While this is invisible to you, your server is still calculating it… on every channel entry loop on every page load (unless you’re in the position where you can cache it). Most of the time we don’t use half of what a channel entry loop offers anyway.

Are you actually showing author data, pagination or categories? If not, then you might want to use a handy parameter in the channel entry loop called “disable” that allows you to… wait for it… disable things in the loop. The great thing is that this is done on a per-loop basis, so you can have a mixture of simple and complex loops across your site.

But sometimes even this isn’t enough. We noticed that the Playa extension was being called on every channel entry loop, even when we just wanted to output a bulleted lists of titles. The performance impact here was worrying. Even with disable=“ categories|category_fields|custom_fields|member_data|pagination” it was still loading in.

Instead we replaced the channel entry loop entirely with a less loved built in module, “Query”.

{exp:query sql="SELECT title, url_title FROM exp_channel_titles WHERE channel_id='10' ORDER BY title ASC;"} {title}{if count!=total_results}, {if:else}.{/if} {/exp:query} It outputs exactly the same HTML with almost none of the performance impact.

The channel entries loop is really useful - but be prepared to go to war with it on occasion. It’s not the only tool in your ExpressionEngine arsenal.

Beware the Add-On

Playa isn’t the only add-on that added to the performance drain of the site. Most add-ons that affect the templates have an impact - and while they’re normally negligible I think the ExpressionEngine community at large has become too reliant on add-ons to make their jobs easier.

Popular add-ons really do have an impact. Earlier this year I completed some basic research on the performance of Stash versus the new built in Layouts engine and for most basic uses Layouts won. The research is online at Github.

It’s so important that you audit your ExpressionEngine sites to evaluate if you actually need an add-on or whether it just adds to the technical debt of the site. Sure, using Plugin A may shave an hour or two off development time - but if it adds collective hours to the load time over the course of the website’s lifetime, was it worth it?

And if you’re massively reliant on add-ons, perhaps ExpressionEngine isn’t even the right choice for the website.


When you use a CMS all day every day it’s easy to miss things that are obvious. You become sheltered and ignore things because "you know best". Sometimes the simplest things can improve a site’s performance considerably.

Don’t take any of the suggestions above at face value. Benchmark your own website with your true environments.

Weigh up the technical debt of everything in your site - be critical about everything and question the apparently obvious. Be prepared to say sacrilegious things like “Let’s use embeds! It’s going to be slower but the debt of maintaining and loading in 5 more snippets is worse”.

A great way to test for spikes in website performance is using Mithra62’s free Debug Toolbar for ExpressionEngine. It clearly visualises problems with your template so you know what to prioritise. Bear in mind though, it adds a bit of processing and one or two SQL queries itself, so only use it for debugging purposes.

If you want to learn more about ExpressionEngine optimisation then Carl Crawley from Made By Hippo is the leading expert in the area. He’ll be speaking at the ExpressionEngine conference in Washington DC later this year with a great talk on how to optimise ExpressionEngine. I had just a taste of what’s to come when speaking with him at GeeUp earlier this year and what he’s come up with is really impressive.