BamlType to make them work.
When you need it
Built-in types (no derive needed):String,booli8,i16,i32,i64,f32,f64Option<T>,Vec<T>,HashMap<String, T>Box<T>,Arc<T>,Rc<T>
#[derive(BamlType)]):
- Your own structs
- Your own enums
- Nested combinations of the above
Structs
Enums
Simple enums
Enums with descriptions
Data enums (tagged unions)
For enums where variants have different fields:tag attribute specifies the discriminator field name. LLM output looks like:
Field attributes
#[baml(alias = "name")]
Rename a field for the LLM:
#[baml(skip)]
Exclude a field from the schema entirely:
Default. It won’t appear in prompts or be expected in responses.
#[baml(default)]
Make a field optional with a default:
Option<T>:
Option<T>- explicitly nullable, LLM can returnnull#[baml(default)]- if LLM omits it, useDefault::default()
#[baml(check(...))] and #[baml(assert(...))]
Add constraints at the type level:
Container attributes
#[baml(rename_all = "...")]
Apply a naming convention to all fields:
"camelCase", "snake_case", "PascalCase", "kebab-case", "SCREAMING_SNAKE_CASE"
#[baml(name = "...")]
Override the type name in the schema:
Advanced: Large integers
Foru64, i128, u128 (which exceed JSON number precision):
Advanced: Map key types
For maps with non-string keys:What’s NOT supported
These will give compile errors:| Pattern | Why |
|---|---|
Tuple structs struct Foo(A, B) | Use named fields instead |
Unit structs struct Foo; | Nothing to serialize |
Tuple enum variants Enum::Var(A) | Use Var { field: A } instead |
serde_json::Value | Too dynamic, use concrete types |
Trait objects dyn Trait | Not serializable |
