Smelter 🔥⚗️
JSON Schema to Elixir code generator. Extracts pure Elixir types from raw JSON Schema ore.
Generates Ecto.Schema modules with embedded_schema and changeset/2 for validation.
Features
-
Full
$refresolution (local, cross-file, JSON pointers) -
Schema composition (
oneOf,anyOf,allOf) $defsextraction and module generation- Enum and const handling
- Format specifiers (date-time, uri, email, uuid)
- Nested object and array handling
- Batch generation from schema directories
Installation
Add smelter to your list of dependencies in mix.exs:
def deps do
[
{:smelter, "~> 0.1.0"}
]
endUsage
Single Schema
# Parse and resolve a schema
{:ok, schema} = Smelter.parse("path/to/schema.json")
# Generate Elixir code
code = Smelter.generate(schema, module: "MyApp.Schemas.User")
# Or do both in one step
{:ok, code} = Smelter.compile("path/to/schema.json", module: "MyApp.Schemas.User")Batch Generation
Smelter can process entire directories of JSON Schemas, preserving the folder structure:
Smelter.Batch.generate(
schema_dir: "priv/schemas/2026-01-11",
output_dir: "lib/my_app/schemas",
module_prefix: "MyApp.Schemas"
)
This processes all .json files in the directory, including:
-
Root schemas with
properties -
Union schemas (
oneOf/anyOf) $defsentries within schemas
Generated Code
Given a JSON Schema like:
{
"title": "User",
"type": "object",
"required": ["name", "email"],
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" },
"age": { "type": "integer", "minimum": 0 }
}
}Smelter generates:
defmodule MyApp.Schemas.User do
@moduledoc """
User
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key false
embedded_schema do
field :age, :integer
field :email, :string
field :name, :string
end
def changeset(struct \\ %__MODULE__{}, params) do
struct
|> cast(params, [:age, :email, :name])
|> validate_required([:email, :name])
end
endSchema Composition
Smelter handles JSON Schema composition keywords:
allOf
Properties from all schemas are merged together:
{
"allOf": [
{ "$ref": "base.json" },
{ "properties": { "extra": { "type": "string" } } }
]
}oneOf / anyOf
Generates union type modules that delegate to the appropriate variant:
{
"oneOf": [
{ "$ref": "error.json" },
{ "$ref": "warning.json" }
]
}
Generated code uses a discriminator field (commonly type) to route to the correct schema module.
$defs
Entries in $defs are extracted and generated as separate modules. A schema like:
{
"$defs": {
"Address": {
"type": "object",
"properties": { "city": { "type": "string" } }
}
}
}
Generates MyApp.Schemas.ContainerName.Address module.
Real-World Usage: Bazaar
Bazaar uses Smelter to generate UCP schemas:
mix bazaar.gen.schemas priv/ucp_schemas/2026-01-11
This generates all Elixir modules in lib/bazaar/schemas/ from the official UCP JSON Schemas.
License
Apache-2.0