Caching in Phoenix/Elixir with Cachex


A quick and dumb-down explanation of how to set up cachex in phoenix/elixir and an optional cache table/service management for awesomeness 😊 . No more chitchat on why caching is important blah blah blah, let’s go straight to coding.

Cachex Installation:

Add cachex to your list of dependencies:

def deps do
[{:cachex, "~> 3.3"}]

Ensure cachex is started before your application:

def application do
[applications: [:cachex]]

Starting your cache:

In your

def start(_type, _args) do
import Supervisor.Spec
children = [

Setup child_spec for your cache:

- must be of type , not a
- must have a unique id

defmodule MyApp.Cache do
@moduledoc """
@cache_table :my_app_cache def child_spec(_init_arg) do
id: @cache_table,
type: :supervisor,
{Cachex, :start_link,
warmers: [
warmer(module: MyApp.CacheWarmer, state: "")

Setting up cache warmer:

defmodule MyApp.CacheWarmer do
@moduledoc """
Cache Warmer

use Cachex.Warmer
alias MyApp.CacheModule

def interval, do: :timer.minutes(60)
def execute(_args) do
with {:ok, data} <- CacheModule.get_data_somewhere() do
{:ok, data, [ttl: :timer.minutes(60)]} end

: Returns the interval this warmer will execute on. (Basically when you want the warmer to rerun)

This must be an integer representing a count of milliseconds to wait before the next execution of the warmer. Anything else will cause either invalidation errors on cache startup, or crashes at runtime.

: Executes actions to warm a cache instance on interval.

This can either return values to set in the cache or an atom to signal that there's nothing to be set at this point in time.

: Time to live, expiration for an entry in a cache.

This is a millisecond value (if set) representing the time a cache entry has left to live in a cache. It can return if the entry does not have a set expiration.

Handling cache on one table (optional):

If you want all your services to share just one cache table, you should parse your data before returning it to the warmer.

defmodule MyApp.CacheModule do
@moduledoc """
Getting Cache Data
alias MyApp.Repo
alias MyApp.Schemas.{
def get_data_somewhere do
with users <- get_data(User, :user),
movies <- get_data(Movie, :movie),
data <- users ++ movies do
{:ok, data}
defp get_data(struct, type) do
|> Repo.all()
|> parse_cache(type)
defp parse_cache(data, type) do
|> f ->
{{type,}, f}

In the method, you want to structure the data like this , you’ll see its use later on in the example.

: is the cache type, in our example, the or

: is the cache key

: is the actual cache data

Examples (if you set up one cache table):

Since we set our application to only have one cache table for all our services/data, using cachex functions will be a little different, but I’m sure you can get it easily

Retrieves an entry from a cache

In cachex documentation:

Cachex.get(:my_cache, "key")

In our app:

Cachex.get(:my_cache, {type, "key"})


Cachex.get(:my_cache, {:user,}){:ok, %User{...}}

Placing an entry in a cache

In cachex documentation:

Cachex.put(:my_cache, "key", "value")

In our app:

Cachex.put(:my_cache, {type, "key"}, "value")


Cachex.put(:my_cache, {:user,}, user){ :ok, true }

And that is it, a quite short blog, but I hope you get the idea, you can have a look at cachex documentation for more details here:, Thanks!

Happy Coding!!

I drink(☕️) and I code things —

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