Mold parses JSON APIs, webhooks, HTTP params and other external input into clean Elixir terms - coerces types, renames keys, checks structure, and returns {:ok, result} or {:error, errors} with traces.
Cheatsheet | Documentation | Hex
Mold.parse(:integer, "42") #=> {:ok, 42}
Mold.parse(:date, "2024-01-02") #=> {:ok, ~D[2024-01-02]}
Mold.parse(%{name: :string, age: :integer}, %{"name" => "Alice", "age" => "25"})
#=> {:ok, %{name: "Alice", age: 25}}
# Options refine the type
Mold.parse({:integer, min: 0, max: 100}, "50") #=> {:ok, 50}
Mold.parse({:atom, in: [:draft, :published]}, "draft") #=> {:ok, :draft}
# Any function works as a type
Mold.parse(&Version.parse/1, "1.0.0")
#=> {:ok, %Version{major: 1, minor: 0, patch: 0}}
# Errors include the path to the failing value
Mold.parse(%{items: [%{name: :string}]}, %{"items" => [%{"name" => "A"}, %{}]})
#=> {:error, [%Mold.Error{reason: {:missing_field, "name"}, trace: ["items", 1], ...}]}
Types are plain data - atoms, tuples, maps, functions. No macros, no structs. A type is just a value you can build at runtime, store in a variable, or compose dynamically.
Mold follows the Parse, don’t validate approach. You parse at the boundary, and from that point on you work with clean Elixir terms. Mold handles structural correctness - business logic is a separate layer.
Also supports: source key mapping with propagation, union types, recursive types, and shared options (nilable, default, in, transform, validate) on all types.
Happy to answer any questions ![]()






















