For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Help on Discord
HomeGuideExamplesBAML ReferencePlaygroundAgents.mdChangelog
HomeGuideExamplesBAML ReferencePlaygroundAgents.mdChangelog
    • Overview
  • baml-cli
    • init
    • generate
    • test
    • serve
    • dev
    • fmt
  • Language Reference
    • Types
    • function
    • test
    • template_string
    • client<llm>
    • class
    • enum
    • generator
  • Generated baml_client
    • with_options(..)
    • AbortSignal / Cancellation
    • Collector
    • logging / env vars
    • AsyncClient / SyncClient
    • TypeBuilder
    • ClientRegistry
    • client Option
    • OnTick
    • Multimodal
    • Image
    • Audio
    • Pdf
    • Video
  • Attributes
    • What are attributes?
    • @alias / @@alias
    • @description / @@description
    • @skip
    • @assert
    • @check
    • Jinja in Attributes
    • @@dynamic
  • LLM Client Providers
    • Overview
    • AWS Bedrock
    • Anthropic
    • Google AI: Gemini
    • Google: Vertex
    • OpenAI
    • OpenAI Responses API
    • OpenAI from Azure
    • OpenRouter
    • openai-generic
    • Microsoft Foundry (openai-generic)
    • Cerebras (openai-generic)
    • Groq (openai-generic)
    • Hugging Face (openai-generic)
    • Keywords AI (openai-generic)
    • Llama API (openai-generic)
    • Litellm (openai-generic)
    • LM Studio (openai-generic)
    • Ollama (openai-generic)
    • Vercel AI Gateway (openai-generic)
    • Tinfoil (openai-generic)
    • TogetherAI (openai-generic)
    • Unify AI (openai-generic)
    • vLLM (openai-generic)
  • LLM Client Strategies
    • Timeout Configuration
    • Retry Policy
    • Fallback
    • Round Robin
  • Prompt Syntax
    • What is jinja?
    • Jinja Filters
    • ctx.output_format
    • ctx.client
    • _.role
    • Variables
    • Conditionals
    • Loops
  • Editor Extension Settings
    • baml.cliPath
    • baml.generateCodeOnSave
    • baml.enablePlaygroundProxy
    • baml.syncExtensionToGeneratorVersion
Help on Discord
LogoLogo
On this page
  • Dynamic Types
  • Modifying Existing Types
  • Creating New Types
  • Type Builders
  • FieldType
  • ClassBuilder
  • ClassPropertyBuilder
  • EnumBuilder
  • EnumValueBuilder
  • Adding Descriptions
  • Creating/modyfing dynamic types with the add_baml method
  • Common Patterns
  • Testing Dynamic Types
  • Future Features
Generated baml_client

TypeBuilder

Was this page helpful?
Edit this page
Previous

Client Registry

Next
Built with

TypeBuilder is used to create or modify output schemas at runtime. It’s particularly useful when you have dynamic output structures that can’t be determined at compile time - like categories from a database or user-provided schemas.

Here’s a simple example of using TypeBuilder to add new enum values before calling a BAML function:

BAML Code

1enum Category {
2 RED
3 BLUE
4 @@dynamic // Makes this enum modifiable at runtime
5}
6
7function Categorize(text: string) -> Category {
8 prompt #"
9 Categorize this text:
10 {{ text }}
11
12 {{ ctx.output_format }}
13 "#
14}

Runtime Usage

Python
TypeScript
Go
Ruby
Rust
1from baml_client.type_builder import TypeBuilder
2from baml_client import b
3
4# Create a TypeBuilder instance
5tb = TypeBuilder()
6
7# Add new values to the Category enum
8tb.Category.add_value('GREEN')
9tb.Category.add_value('YELLOW')
10
11# Pass the typebuilder when calling the function
12result = b.Categorize("The sun is bright", {"tb": tb})
13# result can now be RED, BLUE, GREEN, or YELLOW

Dynamic Types

There are two ways to use TypeBuilder:

  1. Modifying existing BAML types marked with @@dynamic
  2. Creating entirely new types at runtime

Modifying Existing Types

To modify an existing BAML type, mark it with @@dynamic:

Classes
example
1class User {
2 name string
3 age int
4 @@dynamic // Allow adding more properties
5}

Runtime Usage

Python
TypeScript
Ruby
Rust
1tb = TypeBuilder()
2tb.User.add_property('email', tb.string())
3tb.User.add_property('address', tb.string())
Enums
example
1enum Category {
2 VALUE1
3 VALUE2
4 @@dynamic // Allow adding more values
5}

Runtime Usage

Python
TypeScript
Ruby
Rust
1tb = TypeBuilder()
2tb.Category.add_value('VALUE3')
3tb.Category.add_value('VALUE4')

Creating New Types

You can also create entirely new types at runtime:

Python
TypeScript
Ruby
Rust
1tb = TypeBuilder()
2
3# Create a new enum
4hobbies = tb.add_enum("Hobbies")
5hobbies.add_value("Soccer")
6hobbies.add_value("Reading")
7
8# Create a new class
9address = tb.add_class("Address")
10address.add_property("street", tb.string())
11address.add_property("city", tb.string())
12
13# Attach new types to existing BAML type
14tb.User.add_property("hobbies", hobbies.type().list())
15tb.User.add_property("address", address.type())

Type Builders

TypeBuilder provides methods for building different kinds of types:

MethodReturnsDescriptionExample
string()FieldTypeCreates a string typetb.string()
int()FieldTypeCreates an integer typetb.int()
float()FieldTypeCreates a float typetb.float()
bool()FieldTypeCreates a boolean typetb.bool()
literal_string(value: string)FieldTypeCreates a literal string typetb.literal_string("hello")
literal_int(value: int)FieldTypeCreates a literal integer typetb.literal_int(123)
literal_bool(value: boolean)FieldTypeCreates a literal boolean typetb.literal_bool(true)
list(type: FieldType)FieldTypeMakes a type into a listtb.list(tb.string())
union(types: FieldType[])FieldTypeCreates a union of typestb.union([tb.string(), tb.int()])
map(key: FieldType, value: FieldType)FieldTypeCreates a map typetb.map(tb.string(), tb.int())
add_class(name: string)ClassBuilderCreates a new classtb.add_class("User")
add_enum(name: string)EnumBuilderCreates a new enumtb.add_enum("Category")
MyClassFieldTypeReference an existing BAML classtb.MyClass.type()

In addition to the methods above, all types marked with @@dynamic will also appear in the TypeBuilder.

1class User {
2 name string
3 age int
4 @@dynamic // Allow adding more properties
5}
1tb = TypeBuilder()
2tb.User.add_property("email", tb.string())

FieldType

FieldType is a type that represents a field in a type. It can be used to add descriptions, constraints, and other metadata to a field.

MethodReturnsDescriptionExample
list()FieldTypeMakes a type into a listtb.string().list()
optional()FieldTypeMakes a type optionaltb.string().optional()

ClassBuilder

ClassBuilder is a type that represents a class in a type. It can be used to add properties to a class.

MethodReturnsDescriptionExample
add_property(name: string, type: FieldType)ClassPropertyBuilderAdds a property to the classmy_cls.add_property("email", tb.string())
description(description: string)ClassBuilderAdds a description to the classmy_cls.description("A user class")
type()FieldTypeReturns the type of the classmy_cls.type()

ClassPropertyBuilder

ClassPropertyBuilder is a type that represents a property in a class. It can be used to add descriptions, constraints, and other metadata to a property.

MethodReturnsDescriptionExample
description(description: string)ClassPropertyBuilderAdds a description to the propertymy_prop.description("An email address")
alias(alias: string)ClassPropertyBuilderAdds the alias attribute to the propertymy_prop.alias("email_address")

EnumBuilder

EnumBuilder is a type that represents an enum in a type. It can be used to add values to an enum.

MethodReturnsDescriptionExample
add_value(value: string)EnumValueBuilderAdds a value to the enummy_enum.add_value("VALUE1")
description(description: string)EnumBuilderAdds a description to the enum valuemy_enum.description("A value in the enum")
type()FieldTypeReturns the type of the enummy_enum.type()

EnumValueBuilder

EnumValueBuilder is a type that represents a value in an enum. It can be used to add descriptions, constraints, and other metadata to a value.

MethodReturnsDescriptionExample
description(description: string)EnumValueBuilderAdds a description to the enum valuemy_value.description("A value in the enum")
alias(alias: string)EnumValueBuilderAdds the alias attribute to the enum valuemy_value.alias("VALUE1")
skip()EnumValueBuilderAdds the skip attribute to the enum valuemy_value.skip()

Adding Descriptions

You can add descriptions to properties and enum values to help guide the LLM:

Python
TypeScript
Ruby
Rust
1tb = TypeBuilder()
2
3# Add description to a property
4tb.User.add_property("email", tb.string()) \
5 .description("User's primary email address")
6
7# Add description to an enum value
8tb.Category.add_value("URGENT") \
9 .description("Needs immediate attention")

Creating/modyfing dynamic types with the add_baml method

The TypeBuilder has a higher level API for creating dynamic types at runtime. Here’s an example:

Python
TypeScript
Ruby
Rust
1tb = TypeBuilder()
2tb.add_baml("""
3 // Creates a new class Address that does not exist in the BAML source.
4 class Address {
5 street string
6 city string
7 state string
8 }
9
10 // Modifies the existing @@dynamic User class to add the new address property.
11 dynamic class User {
12 address Address
13 }
14
15 // Modifies the existing @@dynamic Category enum to add a new variant.
16 dynamic enum Category {
17 PURPLE
18 }
19""")

Common Patterns

Here are some common patterns when using TypeBuilder:

  1. Dynamic Categories: When categories come from a database or external source
1categories = fetch_categories_from_db()
2tb = TypeBuilder()
3for category in categories:
4 tb.Category.add_value(category)
  1. Form Fields: When extracting dynamic form fields
1fields = get_form_fields()
2tb = TypeBuilder()
3form = tb.add_class("Form")
4for field in fields:
5 form.add_property(field.name, tb.string())
  1. Optional Properties: When some fields might not be present
1tb = TypeBuilder()
2tb.User.add_property("middle_name", tb.string().optional())

All types added through TypeBuilder must be connected to the return type of your BAML function. Standalone types that aren’t referenced won’t affect the output schema.

Testing Dynamic Types

See the advanced dynamic types tests guide for examples of testing functions that use dynamic types. See also the reference for syntax.

Future Features

We’re working on additional features for TypeBuilder:

  • JSON Schema support (awaiting use cases)
  • OpenAPI schema integration
  • Pydantic model support

If you’re interested in these features, please join the discussion in our GitHub issues.