Skip to main content
Types are not just Rust structure. They directly change what the model sees in the system prompt and what the parser accepts in responses. If docs only say “use this attribute” without showing prompt impact, they are not useful. This page is written in user-visible terms.

Mental model

When you add #[BamlType] to a type used in a #[derive(Signature)] output field:
  1. The type is rendered into the schema/instructions sent to the model.
  2. The parser uses the same shape and attributes to parse the model response.
  3. Attributes like alias, skip, and default affect both rendering and parse behavior.

When you need #[BamlType]

Built-in types work without extra annotations:
  • String, bool
  • i8, i16, i32, i64, f32, f64
  • Option<T>, Vec<T>, HashMap<String, T>
  • Box<T>, Arc<T>, Rc<T>
Custom types need #[BamlType]:
  • Your structs
  • Your enums
  • Nested custom types

What the model sees

Example:
use dspy_rs::{BamlType, Signature};

#[derive(Clone, Debug)]
#[BamlType]
#[baml(rename_all = "camelCase")]
struct UserSummary {
    user_name: String,
    created_at: String,
}

#[derive(Signature, Clone, Debug)]
/// Summarize the user.
struct SummarizeUser {
    #[input]
    question: String,

    #[output]
    summary: UserSummary,
}
Prompt-visible effect:
  • Model sees userName and createdAt.
  • Model does not see user_name or created_at.

Attribute impact (visible behavior)

#[baml(alias = "...")]

#[BamlType]
struct User {
    #[baml(alias = "fullName")]
    full_name: String,
}
Visible effect:
  • Prompt/schema uses fullName.
  • Parser accepts model output keyed by fullName.

#[baml(rename_all = "...")]

#[BamlType]
#[baml(rename_all = "camelCase")]
struct ApiResponse {
    user_name: String,
    created_at: String,
}
Visible effect:
  • Prompt/schema keys follow that naming convention.
Options: camelCase, snake_case, PascalCase, kebab-case, SCREAMING_SNAKE_CASE.

#[baml(skip)]

#[BamlType]
struct Doc {
    content: String,
    #[baml(skip)]
    internal_id: u64,
}
Visible effect:
  • internal_id is omitted from the model-facing schema.
Parse effect:
  • Field is filled via Default on parse.

#[baml(default)]

#[BamlType]
struct Config {
    name: String,
    #[baml(default)]
    retries: i32,
}
Visible effect:
  • Field is rendered as optional in schema output.
Parse effect:
  • Missing retries parses as Default::default().

#[baml(name = "...")]

#[BamlType]
#[baml(name = "UserProfile")]
struct User {
    name: String,
}
Visible effect:
  • Typed prompt type labels use UserProfile.
  • Hoisted schema rendering also uses UserProfile.
Important:
  • Default rendering may inline objects, so class headers can be less visible.
  • If you want class headers to be explicit, render with class hoisting enabled.

#[baml(int_repr = "string")]

#[BamlType]
struct BigIds {
    #[baml(int_repr = "string")]
    large_id: u64,
}
Visible effect:
  • Prompt/schema shows large_id as string-like instead of int-like.
Why:
  • Helps with integer widths that exceed JSON number precision.

#[baml(map_key_repr = "string" | "pairs")]

#[BamlType]
struct Scores {
    #[baml(map_key_repr = "string")]
    by_id: std::collections::HashMap<i32, f64>,
}
Visible effect:
  • Controls how non-string map keys are represented to the model.

Enums

Simple enums

#[BamlType]
enum Sentiment {
    Positive,
    Negative,
    Neutral,
}
Visible effect:
  • Prompt/schema presents the allowed literal values.

Data enums (tagged unions)

#[BamlType]
#[baml(tag = "type")]
enum Response {
    Success { data: String },
    Error { code: i32, message: String },
}
Visible effect:
  • Prompt/schema uses type discriminator and variant-specific fields.

Unsupported patterns (compile-time errors)

  • Tuple structs: struct Foo(A, B)
  • Unit structs: struct Foo;
  • Tuple enum variants: Enum::Var(A)
  • serde_json::Value
  • Trait objects (dyn Trait)

Contract tests for these docs

The user-visible claims on this page are locked by tests:
  • Prompt/render effects: crates/dspy-rs/tests/test_bamltype_docs_contract.rs
  • Basic #[BamlType] end-user contract: crates/dspy-rs/tests/test_bamltype_attr_contract.rs
  • Unsupported/compile-fail type shapes: crates/bamltype/tests/ui.rs
  • Signature macro compile-fail coverage: crates/dsrs-macros/tests/ui.rs