> ## Documentation Index
> Fetch the complete documentation index at: https://dsrs.herumbshandilya.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Types

> Define your own types and see exactly how they change the model-facing schema

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:

```rust theme={null}
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 = "...")]`

```rust theme={null}
#[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 = "...")]`

```rust theme={null}
#[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)]`

```rust theme={null}
#[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)]`

```rust theme={null}
#[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 = "...")]`

```rust theme={null}
#[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")]`

```rust theme={null}
#[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")]`

```rust theme={null}
#[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

```rust theme={null}
#[BamlType]
enum Sentiment {
    Positive,
    Negative,
    Neutral,
}
```

Visible effect:

* Prompt/schema presents the allowed literal values.

### Data enums (tagged unions)

```rust theme={null}
#[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`
