This guide covers all configuration options for Memento caches.
Memento has two types of configuration:
When using defmemo or the 2-argument memo, you can mix both in a single map - Memento separates them automatically.
defmemo Macrodefmemo works just like defn - the configuration map is standard Clojure function metadata. You can include any metadata you'd normally use with defn, plus the Memento cache settings:
(require '[memento.core :as m]
'[memento.config :as mc])
;; Always-on caching - specify mc/type
(m/defmemo get-user
{mc/type mc/caffeine}
[user-id]
(db/fetch-user user-id))
;; With additional settings
(m/defmemo get-user
{mc/type mc/caffeine
mc/ttl [5 :m]
mc/size< 1000}
[user-id]
(db/fetch-user user-id))
;; For scoped caching - tags only, no mc/type (no caching until scope entered)
(m/defmemo get-user
{mc/tags [:request]}
[user-id]
(db/fetch-user user-id))
;; With docstring and mixed metadata (cache settings + standard metadata)
(m/defmemo get-user
"Fetches a user by ID."
{mc/type mc/caffeine
mc/ttl [5 :m]
:private true
:added "1.0"}
[user-id]
(db/fetch-user user-id))
memo FunctionWrap an existing function or var:
;; Wrap a function
(def cached-fn (m/memo (fn [x] (* x x)) {mc/type mc/caffeine mc/size< 100}))
;; Wrap a var (modifies the var's root binding)
(defn get-user [user-id] (db/fetch-user user-id))
(m/memo #'get-user {mc/type mc/caffeine mc/ttl [5 :m]})
For advanced control, use 3-argument memo or explicit create + bind:
;; 3-argument memo: fn, mount-conf, cache-conf
(m/memo #'get-user
{mc/tags [:user]} ; mount config
{mc/type mc/caffeine mc/ttl [5 :m] mc/size< 100}) ; cache config
;; Or explicitly
(def my-cache (m/create {mc/type mc/caffeine mc/ttl [5 :m] mc/size< 100}))
(m/bind #'get-user {mc/tags [:user]} my-cache)
These settings control the cache itself. Use vars from memento.config (aliased as mc).
| Option | Description | Example |
|---|---|---|
mc/type | Cache implementation: mc/caffeine or mc/none | {mc/type mc/caffeine} |
mc/size< | Max entries (LRU eviction) | {mc/size< 1000} |
mc/ttl | Time-to-live since creation | {mc/ttl [5 :m]} |
mc/fade | Expiry since last access | {mc/fade [10 :m]} |
mc/initial-capacity | Initial hash table size hint | {mc/initial-capacity 256} |
Time units: :ns, :us, :ms, :s, :m, :h, :d — or just a number for seconds.
Note: If you omit mc/type, the function uses a no-op cache (no caching). This is intentional for scoped caching patterns where caching only happens inside with-caches. See the Scoped Caching Guide.
These settings control how a function connects to its cache.
mc/tagsTags for grouping functions. Used for scoped caching and bulk invalidation.
{mc/tags [:user]} ; Single tag
{mc/tags [:user :request]} ; Multiple tags
;; Shorthand syntax (tags only, no other config)
(m/memo #'get-user :user) ; Same as {mc/tags [:user]}
(m/memo #'get-user [:user :request]) ; Same as {mc/tags [:user :request]}
mc/idIdentifier for the function's cache entries. This determines which entries "belong" to which function when multiple functions share a cache.
Default behavior:
#'get-user): the var name becomes the ID — entries survive namespace reloadsWhen to set explicitly:
Setting an explicit ID allows entries to be shared across function instances and survive reloads:
;; Without mc/id: each call creates a new function with its own empty cache
(defn make-fetcher []
(m/memo (fn [id] (db/fetch id)) {mc/type mc/caffeine}))
;; With mc/id: all instances share the same cache entries, survives reloads
(defn make-fetcher []
(m/memo (fn [id] (db/fetch id)) {mc/type mc/caffeine mc/id :fetcher}))
You can also incorporate closure data into the ID to create separate entry pools per some parameter:
;; Each tenant gets its own cache entries
(defn make-tenant-fetcher [tenant-id]
(m/memo (fn [id] (db/fetch tenant-id id))
{mc/type mc/caffeine mc/id [:tenant-fetcher tenant-id]}))
This works for vars too — nothing prevents you from setting an explicit ID on a var-backed function.
mc/key-fnTransform the argument list into a cache key. Useful when some arguments shouldn't affect caching.
The function receives the arguments as a sequence:
;; Ignore the first argument (e.g., db connection)
(m/defmemo get-user
{mc/key-fn rest} ; Cache key is [user-id], not [db-conn user-id]
[db-conn user-id]
(db/fetch-user db-conn user-id))
;; Extract a specific field from a request
(m/defmemo get-current-user
{mc/key-fn #(-> % first :session :user-id)}
[request]
(db/fetch-user (-> request :session :user-id)))
mc/key-fn*Like key-fn, but receives arguments as separate parameters (like the original function):
(m/defmemo get-user
{mc/key-fn* (fn [db-conn user-id] user-id)}
[db-conn user-id]
(db/fetch-user db-conn user-id))
mc/ret-fnTransform the return value before caching. Receives [args value].
Common uses:
m/do-not-cachem/with-tag-id;; Don't cache error responses
(defn no-cache-errors [[args] response]
(if (>= (:status response) 400)
(m/do-not-cache response)
response))
(m/defmemo get-user
{mc/ret-fn no-cache-errors}
[user-id]
(api/fetch-user user-id))
mc/ret-ex-fnTransform exceptions before they're cached/rethrown. Receives [args throwable].
;; Don't cache transient errors
(defn no-cache-transient [[args] ex]
(if (transient-error? ex)
(m/do-not-cache ex)
ex))
(m/defmemo get-user
{mc/ret-ex-fn no-cache-transient}
[user-id]
(api/fetch-user user-id))
mc/seedPre-populate the cache with initial entries. Map of [args] -> value.
(m/defmemo get-config
{mc/seed {[:database-url] "jdbc:..."
[:api-key] "secret"}}
[key]
(load-config key))
mc/evt-fnEvent handler for cache events. See Advanced Features for details.
Additional options from memento.caffeine.config (aliased as mcc).
mcc/removal-listenerCallback when entries are evicted. Receives [id key value cause].
(require '[memento.caffeine.config :as mcc])
(m/defmemo get-user
{mc/size< 100
mcc/removal-listener (fn [id key value cause]
(println "Evicted:" key "because" cause))}
[user-id]
(db/fetch-user user-id))
Causes: :explicit, :replaced, :collected, :expired, :size
mcc/weight< and mcc/kv-weightWeight-based eviction instead of count-based.
{mcc/weight< 10000000 ; Max total weight
mcc/kv-weight (fn [id key value]
(count (str value)))} ; Weight = string length
mcc/weak-values / mcc/soft-valuesUse weak or soft references for cached values. Allows GC to reclaim entries under memory pressure.
{mcc/weak-values true} ; GC can reclaim anytime
{mcc/soft-values true} ; GC reclaims only under memory pressure
mcc/statsEnable cache statistics collection.
{mcc/stats true}
;; Later, retrieve stats
(m/stats cached-fn)
mcc/tickerCustom time source for testing. Function returning nanoseconds.
{mcc/ticker #(System/nanoTime)}
mcc/expiryVariable per-entry expiry. See Advanced Features.
(ns myapp.cache
(:require [memento.config :as mc]))
(def short-ttl
{mc/ttl [1 :m]
mc/size< 1000})
(def long-ttl
{mc/ttl [1 :h]
mc/size< 10000})
(defn request-scoped [& tags]
{mc/tags (into [:request] tags)})
Then use them:
(m/defmemo get-user
(merge cache/long-ttl (cache/request-scoped :user))
[user-id]
...)
One cache can back multiple functions. This is useful for shared size limits:
;; Both functions share the same 10,000 entry limit
(def user-cache (m/create {mc/size< 10000}))
(m/bind #'get-user {} user-cache)
(m/bind #'get-user-preferences {} user-cache)
;; Check if a function is memoized
(m/memoized? get-user) ; => true
;; Get the original unwrapped function
(m/memo-unwrap get-user)
;; Get cache contents as a map
(m/as-map get-user) ; => {[1] {:id 1 :name "Alice"}, ...}
;; Get the underlying cache instance
(m/active-cache get-user)
;; Get tags for a memoized function
(m/tags get-user) ; => [:user :request]
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |