Exdantic
Exdantic is a schema definition, validation, and JSON Schema toolkit for Elixir. It combines compile-time schema modules with runtime schema generation, typed value adapters, provider-oriented JSON Schema tooling, and environment-driven settings loading.
This project is directly based on Elixact by LiboShen.
Why Exdantic
Exdantic gives you one coherent stack for structured data workflows in Elixir:
- Declarative schema DSL (
use Exdantic) with rich field constraints - Optional struct output with
define_struct: true - Model validators for cross-field logic and transformations
- Computed fields with type-checked derived values
- Runtime schema generation for dynamic workflows
- Type-only validation (
Exdantic.TypeAdapter) for schemaless paths - JSON Schema generation, reference resolution, and LLM-provider shaping
- Environment-to-schema settings loading (
Exdantic.Settings)
Installation
Add Exdantic to your dependencies:
def deps do
[
{:exdantic, "~> 0.1.0"}
]
endThen run:
mix deps.get
Quick Start
1. Define a schema
defmodule UserSchema do
use Exdantic, define_struct: true
schema "User account payload" do
field :name, :string do
required()
min_length(2)
max_length(120)
end
field :email, :string do
required()
format(~r/^[^\s@]+@[^\s@]+\.[^\s@]+$/)
end
field :age, :integer do
optional()
gteq(0)
lteq(150)
end
model_validator :normalize_name
computed_field :email_domain, :string, :compute_email_domain,
description: "Domain part of the email"
config do
title("User")
strict(true)
end
end
def normalize_name(input) do
{:ok, %{input | name: String.trim(input.name)}}
end
def compute_email_domain(input) do
{:ok, input.email |> String.split("@") |> List.last()}
end
end2. Validate and use the result
{:ok, user} =
UserSchema.validate(%{
name: " Jane Doe ",
email: "jane@company.com",
age: 32
})
user.name
# "Jane Doe"
user.email_domain
# "company.com"
{:ok, as_map} = UserSchema.dump(user)3. Generate JSON Schema
schema = UserSchema.json_schema()Runtime and Dynamic Workflows
Exdantic also supports schema creation at runtime:
fields = [
{:answer, :string, [required: true, min_length: 1]},
{:confidence, :float, [required: true, gteq: 0.0, lteq: 1.0]},
{:sources, {:array, :string}, [optional: true]}
]
runtime_schema = Exdantic.Runtime.create_schema(fields,
title: "LLM Output",
strict: true
)
{:ok, validated} = Exdantic.Runtime.validate(%{
answer: "42",
confidence: 0.91
}, runtime_schema)For full runtime pipelines with model validators and computed fields, use
Exdantic.Runtime.create_enhanced_schema/2 and Exdantic.Runtime.validate_enhanced/3.
TypeAdapter, Wrapper, and RootSchema
For one-off or schemaless validation:
{:ok, 123} = Exdantic.TypeAdapter.validate(:integer, "123", coerce: true)For single-field wrapper validation:
{:ok, score} =
Exdantic.Wrapper.wrap_and_validate(
:score,
:integer,
"98",
coerce: true,
constraints: [gteq: 0, lteq: 100]
)For non-map root payloads (RootModel-style):
defmodule IntList do
use Exdantic.RootSchema, root: {:array, :integer}
end
{:ok, [1, 2, 3]} = IntList.validate([1, 2, 3])JSON Schema, LLM, and DSPy Tooling
Exdantic includes advanced schema resolution and provider shaping:
Exdantic.JsonSchema.from_schema/1Exdantic.JsonSchema.Resolver.resolve_references/2Exdantic.JsonSchema.Resolver.enforce_structured_output/2Exdantic.JsonSchema.EnhancedResolver.resolve_enhanced/2Exdantic.JsonSchema.EnhancedResolver.optimize_for_dspy/2
You can validate and generate provider-oriented schemas in one pass via:
Exdantic.EnhancedValidator.validate_with_schema/3Exdantic.EnhancedValidator.validate_for_llm/4Exdantic.EnhancedValidator.comprehensive_validation_report/3
Environment-Driven Settings
Exdantic.Settings loads env values into schema-shaped input, then delegates to
normal validation:
{:ok, settings} =
Exdantic.Settings.from_system_env(MySettingsSchema,
env_prefix: "APP_",
env_nested_delimiter: "__",
ignore_empty: true
)Documentation Map
The full guide set lives under guides/ and is published in HexDocs:
guides/01_overview_and_quickstart.mdguides/02_schema_dsl_and_types.mdguides/03_structs_model_validators_computed_fields.mdguides/04_runtime_schemas.mdguides/05_type_adapter_wrapper_root_schema.mdguides/06_json_schema_and_resolvers.mdguides/07_llm_and_dspy_workflows.mdguides/08_configuration_and_settings.mdguides/09_errors_reports_and_operations.md
Examples
The examples/ directory contains end-to-end scripts for all major capabilities,
including runtime schemas, TypeAdapter, Wrapper, computed fields, model validators,
and LLM-oriented schema flows.
Run examples with:
mix run examples/basic_usage.exs
mix run examples/model_validators.exs
mix run examples/llm_integration.exs
License
Released under the MIT License. See LICENSE.