Back to Baml

with_options

fern/03-reference/baml_client/with_options.mdx

0.222.015.7 KB
Original Source
<Info> Added in 0.79.0 </Info>

The with_options function creates a new client with default configuration options for logging, client registry, and type builders. These options are automatically applied to all function calls made through this client, but can be overridden on a per-call basis when needed.

Quick Start

<Tabs> <Tab title="Python" language="python"> ```python from baml_client import b from baml_py import ClientRegistry, Collector

Simple: just set the client name

my_b = b.with_options(client="openai/gpt-5-mini")

Or with full options for advanced use cases

collector = Collector(name="my-collector") client_registry = ClientRegistry() client_registry.set_primary("openai/gpt-5-mini") env = {"BAML_LOG": "DEBUG", "OPENAI_API_KEY": "key-123"}

Create client with default options

my_b = b.with_options(collector=collector, client_registry=client_registry, env=env)

Uses the default options

result = my_b.ExtractResume("...")

Override options for a specific call

other_collector = Collector(name="other-collector") result2 = my_b.ExtractResume("...", baml_options={"collector": other_collector})

</Tab>

<Tab title="TypeScript" language="typescript">
```typescript
import { b } from "baml_client"
import { Collector, ClientRegistry } from "@boundaryml/baml"

// Simple: just set the client name
const myB = b.withOptions({ client: "openai/gpt-5-mini" })

// Or with full options for advanced use cases
const collector = new Collector("my-collector")
const clientRegistry = new ClientRegistry()
clientRegistry.setPrimary("openai/gpt-5-mini")
const env = {"BAML_LOG": "DEBUG", "OPENAI_API_KEY": "key-123"}

// Create client with default options
const myBAdvanced = b.withOptions({ collector, clientRegistry, env })

// Uses the default options
const result = await myBAdvanced.ExtractResume("...")

// Override options for a specific call
const otherCollector = new Collector("other-collector")
const result2 = await myBAdvanced.ExtractResume("...", { collector: otherCollector })
</Tab> <Tab title="Go" language="go"> <Note> Go doesn't have a `with_options` method like Python/TypeScript. Instead, use individual option functions like `WithClient`, `WithCollector`, `WithClientRegistry`, and `WithEnv` directly in function calls. </Note>
go
package main

import (
    "context"

    b "example.com/myproject/baml_client"
)

func run() {
    ctx := context.Background()

    // Simple: just set the client name
    result, err := b.ExtractResume(ctx, "...", b.WithClient("openai/gpt-5-mini"))
    if err != nil {
        panic(err)
    }

    // Or with full options for advanced use cases
    collector, err := b.NewCollector("my-collector")
    if err != nil {
        panic(err)
    }

    env := map[string]string{
        "BAML_LOG": "DEBUG",
        "OPENAI_API_KEY": "key-123",
    }

    // Make function call with multiple options
    result, err = b.ExtractResume(ctx, "...",
        b.WithClient("openai/gpt-5-mini"),
        b.WithCollector(collector),
        b.WithEnv(env))
    if err != nil {
        panic(err)
    }

    // Override options for a specific call
    otherCollector, err := b.NewCollector("other-collector")
    if err != nil {
        panic(err)
    }
    result2, err := b.ExtractResume(ctx, "...", b.WithCollector(otherCollector))
    if err != nil {
        panic(err)
    }
}
</Tab> <Tab title="Ruby" language="ruby"> ```ruby require 'baml_client'

Set up default options for this client

collector = Baml::Collector.new(name: "my-collector") client_registry = Baml::ClientRegistry.new client_registry.set_primary("openai/gpt-5-mini") env = {"BAML_LOG": "DEBUG", "OPENAI_API_KEY": "key-123"}

Create client with default options

my_b = Baml.Client.with_options(collector: collector, client_registry: client_registry, env: env)

Uses the default options

result = my_b.ExtractResume(input: "...")

Override options for a specific call

other_collector = Baml::Collector.new(name: "other-collector") result2 = my_b.ExtractResume(input: "...", baml_options: { collector: other_collector })

</Tab>

<Tab title="Rust" language="rust">
<Note>
Rust doesn't have a `with_options` method. Instead, use builder methods like `.with_client()`, `.with_collector()`, `.with_client_registry()`, and `.with_env_var()` directly on function calls.
</Note>

```rust
use myproject::baml_client::sync_client::B;
use myproject::baml_client::new_collector;
use baml::ClientRegistry;
use std::collections::HashMap;

fn main() {
    let collector = new_collector("my-collector");

    let mut registry = ClientRegistry::new();
    registry.set_primary_client("openai/gpt-5-mini");

    // Pass options per call using builder methods
    let result = B.ExtractResume
        .with_collector(&collector)
        .with_client_registry(&registry)
        .with_env_var("BAML_LOG", "DEBUG")
        .call("...")
        .unwrap();
}
</Tab> </Tabs>

Common Use Cases

Basic Configuration

Use with_options to create a client with default settings that will be applied to all function calls made through this client. These defaults can be overridden when needed.

<Tabs> <Tab title="Python" language="python"> ```python from baml_client import b from baml_py import ClientRegistry, Collector

def run(): # Configure options collector = Collector(name="my-collector") client_registry = ClientRegistry() client_registry.set_primary("openai/gpt-5-mini")

# Create configured client
my_b = b.with_options(collector=collector, client_registry=client_registry)

# All calls will use the configured options
res = my_b.ExtractResume("...")
invoice = my_b.ExtractInvoice("...")

# Access configuration
print(my_b.client_registry)
# Access logs from the collector
print(collector.logs)
print(collector.last)
</Tab>

<Tab title="TypeScript" language="typescript">
```typescript
import { b } from "baml_client"
import { Collector, ClientRegistry } from "@boundaryml/baml"

const collector = new Collector("my-collector")
const clientRegistry = new ClientRegistry()
clientRegistry.setPrimary("openai/gpt-5-mini")

const myB = b.withOptions({ collector, clientRegistry })

// All calls will use the configured options
const res = await myB.ExtractResume("...")
const invoice = await myB.ExtractInvoice("...")

// Access configuration
console.log(myB.clientRegistry)
console.log(collector.logs)
console.log(collector.last?.usage)
</Tab> <Tab title="Go" language="go"> <Note> Go doesn't support client pre-configuration with `with_options`. Each function call requires options to be passed individually. </Note>
go
package main

import (
    "context"
    "fmt"
    
    b "example.com/myproject/baml_client"
)

func run() {
    ctx := context.Background()
    
    // Configure options for reuse
    collector, err := b.NewCollector("my-collector")
    if err != nil {
        panic(err)
    }
    
    clientRegistry, err := b.NewClientRegistry()
    if err != nil {
        panic(err)
    }
    err = clientRegistry.SetPrimary("openai/gpt-5-mini")
    if err != nil {
        panic(err)
    }
    
    // All calls must explicitly pass options
    res, err := b.ExtractResume(ctx, "...", nil, 
        b.WithCollector(collector), 
        b.WithClientRegistry(clientRegistry))
    if err != nil {
        panic(err)
    }
    
    invoice, err := b.ExtractInvoice(ctx, "...", 
        b.WithCollector(collector), 
        b.WithClientRegistry(clientRegistry))
    if err != nil {
        panic(err)
    }
    
    // Access logs from collector
    logs, err := collector.Logs()
    if err != nil {
        panic(err)
    }
    fmt.Printf("Logs: %+v\n", logs)
}
</Tab> <Tab title="Ruby" language="ruby"> ```ruby require 'baml_client'

collector = Baml::Collector.new(name: "my-collector") client_registry = Baml::ClientRegistry.new client_registry.set_primary("openai/gpt-5-mini")

my_b = Baml.Client.with_options(collector: collector, client_registry: client_registry)

All calls will use the configured options

res = my_b.ExtractResume(input: "...") invoice = my_b.ExtractInvoice(input: "...")

Access configuration

print(my_b.client_registry) print(collector.logs) print(collector.last.usage)

</Tab>

<Tab title="Rust" language="rust">
```rust
use myproject::baml_client::sync_client::B;
use myproject::baml_client::new_collector;
use baml::ClientRegistry;

fn main() {
    let collector = new_collector("my-collector");

    let mut registry = ClientRegistry::new();
    registry.set_primary_client("openai/gpt-5-mini");

    // Pass options per call using builder methods
    let res = B.ExtractResume
        .with_collector(&collector)
        .with_client_registry(&registry)
        .call("...")
        .unwrap();

    let invoice = B.ExtractInvoice
        .with_collector(&collector)
        .with_client_registry(&registry)
        .call("...")
        .unwrap();

    // Access logs from collector
    let logs = collector.logs();
    println!("{:?}", logs);
}
</Tab> </Tabs>

Per-call Tags

Add tags to a specific BAML function call. Tags are useful for correlating requests, A/B versions, user IDs, etc.

<Tabs> <Tab title="Python" language="python"> ```python from baml_client import b from baml_py import Collector

collector = Collector(name="tags-collector") res = b.TestOpenAIGPT4oMini( "hello", baml_options={ "collector": collector, "tags": {"call_id": "first", "version": "v1"}, }, )

print(collector.last.tags)

</Tab>

<Tab title="TypeScript" language="typescript">
```typescript
import { b } from "baml_client";
import { Collector } from "@boundaryml/baml";

const collector = new Collector("tags-collector");
await b.TestOpenAIGPT4oMini("hello", { collector, tags: { callId: "first", version: "v1" } });
console.log(collector.last!.tags);
</Tab> <Tab title="Go" language="go"> ```go ctx := context.Background() collector, _ := b.NewCollector("tags-collector") tags := map[string]string{"callId": "first", "version": "v1"} _, _ = b.TestOpenAIGPT4oMini(ctx, "hello", b.WithCollector(collector), b.WithTags(tags)) logs, _ := collector.Logs() if len(logs) > 0 { t, _ := logs[0].Tags() fmt.Println(t) } ``` </Tab> <Tab title="Rust" language="rust"> ```rust use myproject::baml_client::sync_client::B; use myproject::baml_client::new_collector;

let collector = new_collector("tags-collector"); let result = B.TestOpenAIGPT4oMini .with_collector(&collector) .with_tag("call_id", "first") .with_tag("version", "v1") .call("hello") .unwrap();

let logs = collector.logs(); if let Some(log) = logs.last() { println!("{:?}", log.tags()); }

</Tab>
</Tabs>

### Parallel Execution

When running functions in parallel, `with_options` helps maintain consistent configuration across all calls. This works seamlessly with the [`Collector`](./collector) functionality.

<Tabs>
<Tab title="Python" language="python">
```python
from baml_client.async_client import b
from baml_py import ClientRegistry, Collector
import asyncio

async def run():
    collector = Collector(name="my-collector")
    my_b = b.with_options(collector=collector, client_registry=client_registry)

    # Run multiple functions in parallel
    res, invoice = await asyncio.gather(
        my_b.ExtractResume("..."),
        my_b.ExtractInvoice("...")
    )

    # Access results and logs
    print(res)
    print(invoice)
    # Use tags or iterate logs to correlate specific calls
    for log in collector.logs:
        print(log.usage)
</Tab> <Tab title="TypeScript" language="typescript"> ```typescript import { Collector, ClientRegistry } from "@boundaryml/baml"

const collector = new Collector("my-collector") const myB = b.withOptions({ collector, clientRegistry })

// Run multiple functions in parallel const [ {data: res, id: resumeId}, {data: invoice, id: invoiceId} ] = await Promise.all([ myB.raw.ExtractResume("..."), myB.raw.ExtractInvoice("...") ])

// Access results and logs console.log(res) console.log(invoice) // Use tags or iterate logs to correlate specific calls for (const log of collector.logs) { console.log(log.usage) }

</Tab>

<Tab title="Ruby" language="ruby">
BAML Ruby (beta) does not currently support async/concurrent calls. Reach out to us if it's something you need!
</Tab>
</Tabs>

### Streaming Mode

`with_options` can be used with streaming functions while maintaining all configured options.

<Tabs>
<Tab title="Python" language="python">
```python
from baml_client.async_client import b
from baml_py import Collector

async def run():
    collector = Collector(name="my-collector")
    my_b = b.with_options(collector=collector, client_registry=client_registry)

    stream = my_b.stream.ExtractResume("...")
    async for chunk in stream:
        print(chunk)
    
    result = await stream.get_final_result()
    # Use tags or collector.last / collector.logs for usage
    print(collector.last.usage)
</Tab> <Tab title="TypeScript" language="typescript"> ```typescript import { Collector } from "@boundaryml/baml"

const collector = new Collector("my-collector") const myB = b.withOptions({ collector, clientRegistry })

const stream = myB.stream.ExtractResume("...") for await (const chunk of stream) { console.log(chunk) }

const result = await stream.getFinalResult() // Use tags or collector.last / collector.logs for usage console.log(collector.last?.usage)

</Tab>

<Tab title="Ruby" language="ruby">
```ruby
require 'baml_client'

collector = Baml::Collector.new(name: "my-collector")
my_b = Baml.Client.with_options(collector: collector, client_registry: client_registry)

stream = my_b.stream.ExtractResume(input: "...")
stream.each do |chunk|
    print(chunk)
end

result = stream.get_final_result
# Use tags or collector.last / collector.logs for usage
print(collector.last.usage)
</Tab> <Tab title="Rust" language="rust"> ```rust use myproject::baml_client::sync_client::B; use myproject::baml_client::new_collector;

let collector = new_collector("my-collector");

let mut stream = B.ExtractResume .with_collector(&collector) .stream("...")?;

for partial in stream.partials() { println!("{:?}", partial?); }

let result = stream.get_final_response()?; // Access usage from collector println!("{:?}", collector.usage());

</Tab>
</Tabs>

## API Reference

### with_options Parameters

<Note>
These can always be overridden on a per-call basis with the `baml_options` parameter in any function call.
</Note>

| Parameter | Type | Description |
|-----------|------|-------------|
| `client` | `string` | Client name to use for all calls (shorthand for `client_registry.set_primary()`) |
| `collector` | [`Collector`](/ref/baml_client/collector) | Collector instance for tracking function calls and usage metrics |
| `client_registry` | `ClientRegistry` | Registry for managing LLM clients and their configurations |
| `type_builder` | [`TypeBuilder`](/ref/baml_client/type-builder) | Custom type builder for function inputs and outputs |
| `env` | `Dict/Object` | Environment variables to set for the client |
| `tags` (per-call) | `Dict/Object` | Arbitrary metadata for this call; merged with parent trace tags |

### Configured Client Properties

<Info>
The configured client maintains the same interface as the base `baml_client`, so you can use all the same functions and methods.
</Info>


## Related Topics
- [Collector](/ref/baml_client/collector) - Track function calls and usage metrics
- [TypeBuilder](/ref/baml_client/type-builder) - Build custom types for your functions
- [Client Registry](/ref/baml_client/client-registry) - Manage LLM clients and their configurations
- [Environment Variables](/ref/baml/general-baml-syntax/environment-variables) - Set environment variables
- [AbortController](/ref/baml_client/abort-signal) - Cancel in-flight operations

<Info>
The configured client maintains the same interface as the base client, so you can use all the same functions and methods.
</Info>