malli 2026-02-19

I'm reading the malli documentation, and I'm kinda confused on the difference between mr/composite-registry and just mergeing schemas into a registry. There are lots of examples that just merge schemas into a registry like this:

(def registry (merge (m/default-schemas) (mu/schemas)))
but there are also examples that create a registry using mr/composite-registry like this:
(mr/set-default-registry!
  (mr/composite-registry
    (m/default-schemas)
    (met/schemas)))
what is the actual difference? I want to include mu/schemas for :merge schema into the default registry, what should I use and why?

If the registries you are merging are maps, there is no difference. Internally, mr/registry is always called coercing to Registry. mr/composite-registry, mr/set-default-registry! both do this. The one case you should be careful about when using merge on non-map registries like (merge (mr/composite-registry ..) (mr/composite-registry ..)). This won't work.

> I want to include mu/schemas for :merge schema into the default registry, what should I use and why? Either will work, because mu/schemas is a map, and set-default-registry! coerces to Registry internally.

It's worth noting that merge has a performance advantage over composite-registry. The latter iterates over multiple lookups instead of pouring them into the same map.

ah thanks for the explanation!

👍 1

It seems that circular schema references stop working when 'resetting' the default registry, poc:

(malli-registry/set-default-registry!
   (malli/default-schemas))

  (def sample-tree-schema
    [:map
     [:value :int]
     [:children {:optional true}
      [:vector
       [:ref #'sample-tree-schema]]]])

  (malli/assert
   sample-tree-schema
   {:value 1
    :children
    [{:value 2
      :children [{:value 4}]}
     {:value 3}]})

=> :malli.core/invalid-ref
any idea why?

Any ideas on how to improve the documentation?

Guessing you need to add var-registry to the default registry https://github.com/metosin/malli?tab=readme-ov-file#var-registry

i.e., (composite-registry (default-schemas) (var-registry))

so malli/default-registry is not malli/default-schemas by default

kinda confusing

Under the hood, m/default-registry is a map of schemas, but mr/var-registry is a Registry. It's a good example of the difference between using merge and composite-registry here, merge wouldn't work.

It's a leaky abstraction but it might be a little less confusing in practice knowing that.

Leaky because default-registry doesn't document whether it's a map or a Registry, but we always assume it's a map just because it's more convenient (merge, assoc, select-keys).

thanks again for the explanation, I too found out its a documentation issue

👍 1