Speed up your Craft CMS Templates with Eager Loading
Tags: frontend, webperf, craftcms
Published: 2020-02-19 22:09:58

---
title: Speed up your Craft CMS Templates with Eager Loading
published: true
date: 2017-09-30 04:00:00 UTC
tags: frontend,webperf,craftcms
canonical_url: https://nystudio107.com/blog/speed-up-your-craft-cms-templates-with-eager-loading
---

Published: <time datetime="Sat, 30 Sep 2017 00:00:00 -0400">2017.09.30</time> / Updated: <time datetime="Mon, 03 Jun 2019 11:29:27 -0400">2019.06.03</time>

# Speed up your Craft CMS Templates with Eager Loading

### Eager-Load­ing Ele­ments allows you to speed up your Craft CMS tem­plates by fetch­ing entries from the data­base more efficiently.

Andrew Welch / [nystudio107](https://nystudio107.com)

![Craft Cms Eager Loading Elements](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/craft-cms-eager-loading-elements.jpg)

One of the won­der­ful things about [Craft CMS](https://craftcms.com/) is that you have great flex­i­bil­i­ty in design­ing both the fron­tend and the back­end of your website.

This is due in large part to Craft’s con­cept of [Ele­ments](https://craftcms.com/docs/plugins/working-with-elements). Most of the things you inter­act with on the back­end such as Entries, Cat­e­gories, Assets, Users, and even Matrix blocks are all Ele­ments. Ele­ments are all stored sep­a­rate­ly, so any ref­er­ence from one Ele­ment to anoth­er is a _rela­tion_.

So if you cre­ate an Entry with an Asset field in it, the Asset isn’t actu­al­ly stored in the Entry itself; instead, the Entry Ele­ment just points to the Asset Element.

<aside>
                                This is a key con­cept, because under­stand­ing how Ele­ments are stored allows you to under­stand how they are loaded
                            </aside>

The fol­low­ing things in Craft CMS are all Elements:

- Assets
- Cat­e­gories
- Entries
- Glob­al Sets
- Matrix Blocks
- Tags
- Users

There are also Ele­ments added by some plu­g­ins, such as [Craft Com­merce](https://craftcommerce.com/) Products.

Let’s take a very sim­ple exam­ple of a code pat­tern you prob­a­bly see every day:

```

{% for entry in craft.entries.section('blog').limit(null) %}
    <img src="{{ entry.blogImage.first().url }}" alt="{{ entry.title }}" />
{% endfor %}

```

Here we’re just loop­ing through all of our Entries in the <kbd>blog</kbd> sec­tion, and out­putting the <kbd>blogImage</kbd> Asset url in an <kbd>&lt;img&gt;</kbd> tag.

In order to do this, Craft has to first fetch all of the <kbd>blog</kbd> Entries, so it knows how many <kbd>blog</kbd> Entries there are. Then each time through the loop it access­es the <kbd>blogImage</kbd> Asset to get its URL.

But remem­ber the Asset Ele­ment isn’t actu­al­ly stored in the Entry Ele­ment, it’s a rela­tion that _points_ to the Asset Ele­ment. So each time through the loop, Craft has to do _anoth­er_ data­base access to get the Asset Ele­ment. Only then can it out­put the URL.

<aside>
                                Data­base access­es are cost­ly, because they require build­ing a query, then access­ing the data­base, which then reads from the stor­age device
                            </aside>

This is a clas­sic <kbd>n+1</kbd> prob­lem, which just means that as the num­ber of things goes up, the time it takes to do some­thing with them increas­es linearly.

This is rough­ly equiv­a­lent to ask­ing your sig­nif­i­cant oth­er to run to the store to pick some­thing up for you… and then as soon as they get back, you ask them to run back out and pick up some­thing else. And then repeat this dozens, or even hun­dreds of times. Don’t try this at home, folks.

![Woman Headache](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/woman-headache.jpg)

Nor­mal­ly this type of ​“lazy load­ing” that Craft does is a good thing, because it can’t know what rela­tions you’ll need to access ahead of time. If Craft loaded _every­thing_ every time, it’d be like buy­ing out the entire store with­out regard for what you actu­al­ly need.

So Craft just loads rela­tions like Assets as you access them. But this also can be inef­fi­cient if we _know_ we’re going to need cer­tain things.

If only there was a way to _tell_ Craft what we need ahead of time…

## Enter Eager-Load­ing Elements

Con­sid­er our the­o­ret­i­cal (and poten­tial­ly dan­ger­ous) shop­ping anal­o­gy. Instead of adding anoth­er round trip to the store for our sig­nif­i­cant oth­er for each thing we want, would­n’t it be nice if we did some­thing sen­si­ble? Some­thing like prepar­ing a shop­ping list ahead of time, and poten­tial­ly sav­ing our relationship?

<aside>
                                This is exact­ly what Eager Load­ing allows you to do: tell Craft ahead of time what you’re going to need
                            </aside>

Craft CMS intro­duced the con­cept of [Eager-Load­ing Ele­ments](https://craftcms.com/docs/templating/eager-loading-elements) in Craft 2.6. Lever­ag­ing Eager-Load­ing Ele­ments, our exam­ple would change to be this:

```

{% for entry in craft.entries.section('blog').with(['blogImage']).limit(null) %}
    <img src="{{ entry.blogImage[0].url }}" alt="{{ entry.title }}" />
{% endfor %}

```

Two things to note here:

- We added <kbd>.with(['blogImage'])</kbd> to our <kbd>craft.entries</kbd>, which tells Craft ​“Hey, while you’re fetch­ing these entries, we want all of the <kbd>blogImage</kbd> Asset Ele­ments, too”
- We changed <kbd>.first()</kbd> to <kbd>[0]</kbd> (tech­ni­cal­ly, we’re going from Object syn­tax to Array syntax)

What’s hap­pened here is we’ve asked Craft to give us our Entries, and while it’s fetch­ing them, to also fetch each <kbd>blogImage</kbd> Asset Ele­ment in each Entry, too. 

Under the hood, when you ask for Entries that have rela­tions to oth­er Ele­ments, the thing you get back is an [Ele­ment­Cri­te­ri­aMod­el](https://craftcms.com/docs/templating/elementcriteriamodel) that tells Craft how to retrieve the Ele­ment (in this case, an Asset). But it does­n’t _actu­al­ly_ retrieve it until you access it. This is lazy loading.

When you ask for Entries with rela­tions to oth­er Ele­ments that are Eager Loaded, instead of an <kbd>ElementCriteraModel</kbd>, Craft fetch­es the rela­tions and returns an array of the Asset ele­ments. Thus the change from <kbd>.first()</kbd> Object syn­tax to <kbd>[0]</kbd> Array syntax.

For details on the syn­tax you can use for Eager Load­ing, check out the Craft help arti­cle [Eager-Load­ing Ele­ments](https://craftcms.com/docs/templating/eager-loading-elements).

## Real World Examples

The rea­son we want to use Eager Load­ing is to reduce the num­ber of SQL data­base queries need­ed to load a page, and thus increase performance.

So let’s take a look at some real world examples.

![Welcome To The Real World](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/welcome-to-the-real-world.jpg)

We will once again use this web­site you’re read­ing right now as our guinea pig. Here’s what the Field Lay­out looks like for our <kbd>blog</kbd> section:

![Blog Field Layout](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_992x724_crop_center-center_100_line/blog-field-layout.png)

Here’s what the fields actu­al­ly are:

- Blog Cat­e­go­ry → Cat­e­go­ry _Ele­ment_
- Blog Tags → Tag _Ele­ment_
- Blog Sum­ma­ry → Rich Text Field
- Blog Image → Asset _Ele­ment_
- Blog Con­tent → Matrix Block _Ele­ment_
- Blog SEO → [SEO­mat­ic](https://github.com/nystudio107/seomatic) Meta

So it’s a pret­ty sim­ple set­up, we only have 6 fields, but 4 out of the 6 fields are Ele­ments, and thus are rela­tions that we could be Eager Load­ing. The Blog Con­tent field is a ​“con­tent builder” Matrix Block for our blog con­tent, as described in the [Cre­at­ing a Con­tent Builder in Craft CMS](https://dev.to/gaijinity/creating-a-content-builder-in-craft-cms-29ap-temp-slug-2753628) article.

The Matrix Blocks for the Blog Con­tent look like this:

![Content Builder Image Block](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x830_crop_center-center_100_line/content-builder-image-block.png)

Only the <kbd>image</kbd> Matrix Block type has a rela­tion, in that it has an Asset Ele­ment in it (actu­al­ly a [Focus Point](https://github.com/smcyr/Craft-FocusPoint) field, but it’s the same thing).

The first thing we should do before we address any per­for­mance issues is to gath­er data to see where the per­for­mance bot­tle­necks are. All of the tim­ing tests are done in local dev on our [Home­stead VM](https://dev.to/gaijinity/local-development-with-vagrant-homestead-5gb0-temp-slug-2094211), with [dev­Mode](https://craftcms.com/support/dev-mode) on and all caching is dis­abled so we can see the raw results. 

Because we’re doing all of these tim­ing tests in an envi­ron­ment with all sorts of debug­ging enabled, it’s going to be sig­nif­i­cant­ly slow­er in absolute terms than on <kbd>live</kbd> pro­duc­tion. How­ev­er, the rel­a­tive tim­ings should be rough­ly similar.

Here are the data­base queries for the [Blog Index](https://nystudio107.com/blog) page:

![Blog Index Queries Normal](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x412_crop_center-center_100_line/blog-index-queries-normal.png)

Wow, so we have <kbd>120</kbd> data­base queries just to dis­play a sim­ple page of the 9 most recent blog entries, and a thumb­nail image of each. Also don’t just look at the num­ber of queries, look at the time: <kbd>1.24399s</kbd>

Here’s what the code looks like that loads our entries:

```

{% set entries = craft.entries ({
            section: 'blog',
            order: 'postDate desc',
            limit: limitBlogs,
            relatedTo: relatedBlogs,
        }) %}

        {% for entry in entries %}

```

Let’s apply a bit of what we’ve learned, and Eager Load some of these Ele­ments that are in our Entry as relations:

```

{% set entries = craft.entries ({
            section: 'blog',
            with: ['blogImage', 'blogCategory', 'blogTags'],
            order: 'postDate desc',
            limit: limitBlogs,
            relatedTo: relatedBlogs,
        }) %}

        {% for entry in entries %}

```

So we’ve just added the line <kbd>with: ['blogImage', 'blogCategory', 'blogTags'],</kbd> to tell Craft we want to Eager Load these things, because we know we’ll be using them.

Note that even though the <kbd>blogContent</kbd> is a Matrix Block Ele­ment, and thus it could be a can­di­date for Eager Load­ing, we’re not ask­ing for it to be Eager Loaded. That’s because we’re not using the <kbd>blogContent</kbd> at all on the Blog Index page, so there’s no rea­son to load it!

So how’d we do? Here’s what the tim­ings look like after we’ve added Eager Loading:

![Blog Index Queries Eager Loading](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x409_crop_center-center_100_line/blog-index-queries-eager-loading.png)

Holy moly! We near­ly cut the num­ber of queries in half, down to <kbd>62</kbd> queries from <kbd>120</kbd>, and the time down to <kbd>1.03165s</kbd> from <kbd>1.24399s</kbd>. That’s a <kbd>49%</kbd> sav­ings in the num­ber of queries, and an <kbd>18%</kbd> sav­ings in the amount of time that it took.

![In A Vacuum Of Space](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/in-a-vacuum-of-space.jpg)

While an <kbd>18%</kbd> sav­ings in time may not seem like a big deal in a vac­u­um, in real world con­di­tions where there are mul­ti­ple peo­ple hit­ting your web­site con­cur­rent­ly, there will be con­tention for the data­base that snow­balls. Every­one has to get in line to have their data­base queries ful­filled, so any delay can have a cas­cad­ing effect on the web­site’s performance.

Our Blog Index page is pret­ty light­weight any­way, it only loads the most recent 9 blog entries. Let’s scale it up a bit, and have it load all of the blog entries on the page (about 40 at cur­rent count):

![Blog Index Queries Normal All](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x394_crop_center-center_100_line/blog-index-queries-normal-all.png)

Now we’re up to a whop­ping <kbd>352</kbd> queries that takes <kbd>3.25565s</kbd>. Let’s see what it looks like if we add in Eager Loading:

![Blog Index Queries Eager Loading All](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x388_crop_center-center_100_line/blog-index-queries-eager-loading-all.png)

With Eager Load­ing added, we’ve got­ten it down to <kbd>120</kbd> queries from <kbd>352</kbd> queries, and the time down to <kbd>2.42931s</kbd> from <kbd>3.25565s</kbd>. That’s a <kbd>76%</kbd> sav­ings in the num­ber of queries, and a <kbd>26%</kbd> sav­ings in the amount of time that it took.

I think it’s pret­ty clear that as the num­ber of things goes up, the sav­ings we get from Eager Load­ing just gets bet­ter and bet­ter. This will make our web­site scale up nice­ly as the client adds content.

## Eager Load All The Things!

Keep in mind that although the exam­ple we used was with Entry Ele­ments, any­thing that’s an Ele­ment can poten­tial­ly have rela­tions to oth­er Elements.

![Eager Load All The Things](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_768x576_crop_center-center_100_line/eager-load-all-the-things.png)

For exam­ple, you might have added Cat­e­go­ry fields to your Assets. These too are things that are rela­tions, can be eager loaded, for example:

```

{% set asset = entry.blogImage.with(['someCategory']).first() %}

```

You can even [Eager Load Nest­ed Sets of Ele­ments](https://craftcms.com/docs/templating/eager-loading-elements#eager-loading-nested-sets-of-elements) like this:

```

{% set entries = craft.entries ({
            section: 'blog',
            with: ['blogImage.someCategory', 'blogCategory', 'blogTags'],
            order: 'postDate desc',
            limit: limitBlogs,
            relatedTo: relatedBlogs,
        }) %}

        {% for entry in entries %}

```

The ​“dot syn­tax” <kbd>'blogImage.someCategory'</kbd> tells Craft to Eager Load the <kbd>blogImage</kbd> Asset from the Entry, and while it’s at it, also Eager Load the <kbd>someCategory</kbd> Cat­e­go­ry from the Asset.

<aside>
                                Most every­thing in Craft is an Ele­ment; you can Eager Load any Ele­ment into any Ele­ment, even nest­ed Elements!
                            </aside>

This ends up being a pret­ty pow­er­ful way to design your back­end con­ve­nient­ly with nest­ed Ele­ments, but not suf­fer a per­for­mance penal­ty on the fron­tend when you go to load them.

Just tell Craft what you want Eager Loaded — no mat­ter how deeply nest­ed — and away you go!

## What About Auto-Inject­ed Entry’s?

One nice thing that Craft does for you is it auto-injects an <kbd>entry</kbd> or <kbd>category</kbd> vari­able for Entry or Cat­e­go­ry Tem­plates. It’s a nice con­ve­nience, because then you can just access the <kbd>entry</kbd> vari­able with­out wor­ry­ing about pars­ing the URL, and load­ing the appro­pri­ate Entry.

The only down­side is because the Entry has already been loaded, we don’t get a chance to tell Craft what we want Eager Loaded <kbd>with</kbd> that Entry.

Remem­ber, though, that our Entry will get pre­loaded with the Ele­ment­Cri­te­ri­aMod­el for any of the Ele­ments that are lazy loaded. So we can just do some­thing like we did in the first exam­ple to eager load Ele­ments that are in our entry: 

```

{% set blocks = entry.blogContent.with(['image:image']) %}

{% for block in blocks %}

```

What we’re doing is ask­ing Craft to load all of our <kbd>blogContent</kbd> Matrix Block Ele­ments with the field <kbd>image</kbd> for any Matrix Block of the type <kbd>image</kbd>.

This is cer­tain­ly bet­ter than lazy load­ing the <kbd>image</kbd> Asset every time through the loop, but it can end up being a lit­tle ver­bose in your tem­plates, espe­cial­ly if you have a whole lot of Ele­ments in your Entries that you have to explic­it­ly Eager Load.

![Eager Beaver](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/eager-beaver.jpg)

So I wrote a small plu­g­in [Eager Beaver for Craft 2.6.x](https://github.com/nystudio107/eagerbeaver) & [Eager Beaver for Craft 3.x](https://github.com/nystudio107/craft3-eagerbeaver). This plu­g­in just lets you use the same Eager Load­ing syn­tax for already loaded <kbd>entry</kbd> (or what­ev­er) Ele­ments that you use for Ele­ments that you load yourself.

For exam­ple, this is what I use on <kbd>_entry.twig</kbd> tem­plate for each Blog entry:

```

{% do eagerLoadElements(entry, [
    'author.userPicture',
    'blogCategory',
    'blogImage',
    'blogContent.image:image'
]) %}

```

The first para­me­ter to <kbd>eagerLoadElements()</kbd> is just the Ele­ment we want to eager load things into, and the sec­ond para­me­ter is the same <kbd>with</kbd> that you use for nor­mal [Eager-Load­ing Ele­ments](https://craftcms.com/docs/templating/eager-loading-elements).

I pre­fer Eager Load­ing every­thing in one fell swoop this way, rather than doing it _à la carte_ through­out my tem­plates. But either method works, use what­ev­er you prefer.

Note that on Craft 3, you can do the exact same thing that the Eager Beaver plu­g­in does by using <kbd>craft.app.elements.eagerLoadElements</kbd>:

```

{% do craft.app.elements.eagerLoadElements(
    className(entry),
    [entry],
    ['assetsField', 'categoriesField.assetField', 'matrixField.blockType:assetsField']
) %}

```

The first para­me­ter is the class name of the ele­ment type we’re eager load­ing ele­ments into (in this case, an entry). The sec­ond para­me­ter is an array of ele­ments we’re eager load­ing ele­ments into (in this case, an array with just our entry in it). Final­ly, the third para­me­ter is dot-nota­tion of what ele­ments we want to eager load. c.f.: [eager­Load­Ele­ments()](http://docs.craftcms.com/api/v3/craft-services-elements.html#method-eagerloadelements)

## What About the Ele­ment API?

Some­thing that is get­ting more and more com­mon these days is Craft being accessed via the [Ele­ment API](https://github.com/craftcms/element-api/tree/v1) by fron­tend JavaScript or oth­er ser­vices. This is exact­ly how we did things in the [Auto­com­plete Search with the Ele­ment API & Vue­JS](https://dev.to/gaijinity/autocomplete-search-with-the-element-api-vuejs-4ae4-temp-slug-4112251) article.

Well, we can use Eager Load­ing in the Ele­ment API as well! We can just do some­thing like this:

```

<?php
namespace Craft;

return [
    'endpoints' => [
        'api/search' => [
            'elementType' => 'Entry',
            'paginate' => false,
            'criteria' => [
                'section' => 'blog',
                'with' => [
                    'blogCategory',
                    'blogTags'
                ],
                'limit' => 9,

```

Note the <kbd>with</kbd> key; look famil­iar? Yep, we can eager load things here just like we can every­where else.

It’s impor­tant not to over­look opti­miz­ing your API end­points like this as well, espe­cial­ly as they become more and more com­mon­ly used.

## Don’t Be Too Eager

We’ve focused on using caching to help with per­for­mance in the [The Craft `{% cache %}` Tag In-Depth](https://dev.to/gaijinity/the-craft-cache-tag-in-depth-207b-temp-slug-8529389) and the [Sta­t­ic Page Caching with Craft CMS](https://dev.to/gaijinity/static-page-caching-with-craft-cms-4kk9-temp-slug-2093610) arti­cles. It’s impor­tant to not use caching as a way to mask or var­nish-over per­for­mance problems.

![Varnishing Over](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/varnishing-over.jpg)

We should opti­mize our tem­plates with things like Eager Load­ing _before_ we add a caching lay­er on top to help with concurrency.

We don’t want our cache miss­es to bog down the web­site, and real­ly, things like Eager Load­ing are pret­ty sim­ple to do.

Go forth, and Eager Load!

## Further Reading

_If you want to be notified about new articles, follow [nystudio107](https://twitter.com/nystudio107) on Twitter._

<small>Copyright ©2020 nystudio107. Designed by nystudio107</small>