Ecto Preloads in Phoenix Contexts

Are not as difficult as they seem

Photo by Jude Beck on Unsplash
Photo by Jude Beck on Unsplash
Photo by Jude Beck on Unsplash

When I’m working with a new Phoenix app (written in Elixir), I often come across the following situation. I happened to run into it last night on a side-project I’m building called Remind Me (which you should definitely check out, it’s free and it will help you stay on top of a whole class of to-do’s that often fall through the cracks), so I decided to write up my thoughts on the subject. Here’s the issue (with fake resource names for illustration):

  • I have a few associated resources in my database, like a which has_many ‘s and has_one
  • I have a context, which when generated by default has a function like this:
  • I need to be able to get a few ’s out of the database and send them to the front-end (or through GraphQL or whatever is needing the data) with the associated 's and preloaded.
  • I hate having to make a function like this to do the work:

Because as soon as I need another preload or I don’t need one of them, I have to make related functions like and so on. Over time you end up with long function names and the callers are always receiving more or less data than the really need (usually more than needed, which can become a performance problem).

So here’s a more elegant solution.

In the context, e.g. :

The first thing we’re doing here is adding a keyword list as a parameter, with an empty list as the default value.

Then, we’re checking the keyword list for the option, and if it doesn’t exist in we’ll default to an empty list.

We rely on the behavior of , which just returns the struct(s) in the first argument if you pass an empty list as the second argument.

Modifying the function this way gives the calling function ultimate flexibility: it can choose to preload only the associations it needs, to get the minimum amount of data back as possible.

For example, in the controller or resolver, e.g. :

As a bonus, this approach even works with nested preloads! Imagine that each had many ‘s, we could preload those like this:


In software, most decisions aren’t about the “right” or “wrong” way to do things, but rather they’re about tradeoffs.

The solution I’ve proposed here has some advantages:

  • Simplicity
  • Easy to read and reason about
  • Maintainable

But it also has a disadvantage: it requires multiple trips to the database.

Any time you use or the equivalents (more on that syntax in a minute), each item (including nested preloads) will generate a separate query. So in our example, where our list of preloads looks like , we will have three queries: one to fetch the ’s, another to fetch the associated ’s, and another to fetch the .

With two preloaded associations, it’s probably not that bad and unless you’re developing for scale that demands optimizing every query to the hilt, it’s probably worth a couple extra trips to the database for the code readability. In addition, you’ll keep your context nice and tidy while requirements are added, and by the time the query becomes a bottleneck you’ll have a much more mature idea of what preloads you really need from the query.


So say you are at the point where every trip to the database makes a big difference, whether it’s about page load times or the stress on the database.

There is a great article put out by ThoughtBot that details this exact issue of preloads causing multiple database queries, and some of the solutions.

The basic idea for optimizing preloads is that you need to use the syntax and join the associations yourself. Here’s one way to do it, but we’re back to the dilemma of having long function names, and it’s not nearly as pretty:

In Conclusion

Ecto is a very powerful tool with a whole range of functions to help you interact with a database at any level of abstraction you like.

When development speed is of the essence, Ecto has high-level abstractions to make your life easy and your code beautiful. It’s easy to maintain and extend, and will keep your development cycle short while you’re building and iterating rapidly.

But, when your app hits scale and performance becomes critical, Ecto has the tools for you to get down into the nitty gritty SQL layers while still writing safe, expressive, composable queries.


There is a great macro solution from joshnuss in the comments that allows you to join and preload in one step:

It looks really promising (and I tested it and it works great!) and it gives me hope that there are elegant solutions within reach to keep the maintainability and simplicity of piping in preloads from a caller, without multiple queries to the database.

Written by

Elixir dev building for the web with Phoenix

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store