sorry if the following question is too basic, but I've spent quite some time digging now so I decided to reach out for help.

Is 250 DB queries too many?

I have a Neo field "modules" that can contain different ~30 other fields for content, such as "Headline", "WYSISG Block", "Buttons", etc. I think this is a common pattern for CraftCMS. The modules are then rendered as follows:

{% for module in entry.modules %} 
    {% include alias('@organisms/o-' ~ module.type.handle|replace('/(?<!^)[A-Z]/', '-$0')|lower) ignore missing with module %}
{% endfor %}

With 14 content blocks this results in ~250 DB queries -- is this too many?

Reducing the number of queries

I tried to bring the number of queries down by eager-loading, adding the following:

{% set eagerLoadedModules = entry.modules.with(
).all() %} 

{% for module in eagerLoadedModules %} 
    {% include alias('@organisms/o-' ~ module.type.handle|replace('/(?<!^)[A-Z]/', '-$0')|lower) ignore missing with module  %}
{% endfor %}

However, this did not reduce the number of queries compared to the "dummy" version. I thought the problem was that eager-loading is rather meant for "N+1 queries" situations which is not really my use-case. I hoped that CraftCMS would merge the eager-load into one big query, but it seems to not be the case.

Can you please provide me with code examples and pointers on how to bring the number of queries down in this case?

  • Craft: 3.9.6
  • Neo: 2.13.19


1 Answer 1


Sorry I've never used Neo before, but I'll answer as if it were a standard Craft matrix field, as I'd expect/hope that it would work the same way(?!):

  1. First, correct your syntax: In entry.modules.with... you're already in the context of your field called modules, so you shouldn't repeat the modules. ... part at the start of each eager loadable thing.

  2. Second, there is no value in eager loading things that are not relationships pointing to other elements, ie: assets, categories, entries, users, or tags. So don't attempt to eager load text fields and lightswitches - it's meaningless.

  3. For assets, don't forget to also eager load any transforms that you might be using.

Syntax might then look like this:

{% set eagerLoadedModules = entry.modules.with([
    ['headlineWithContent:backgroundImage', {withTransforms: arrayOfTransforms1}],
    ['headlineWithContent:backgroundImageMobile', {withTransforms: arrayOfTransforms2}]
]).all() %}

Depending on how you set your transforms (control panel vs templates vs something custom like in config/custom.php) your transform arrays might look something like this:

{% set arrayOfTransforms1 = [
    {width: 1980},
    {width: 1700},
    {width: 1200},
    {width: 800},
    {width: 1980, format: 'webp'},
    {width: 1700, format: 'webp'},
    {width: 1200, format: 'webp'},
    {width: 800, format: 'webp'},
] %}

{% set arrayOfTransforms2 = [
    {width: 900, height: 900, mode: 'crop'},
    {width: 500, height: 500, mode: 'crop'},
] %}

(Aside: to avoid manual duplication of the webp variants, and also to make my transforms available globally without bumping into awkward Twig parse order issues, I put mine in config/custom.php like this: https://github.com/cld-agency/craftwind-boilerplate/blob/craft-4/config/custom.php)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.