Model or dataset
BoundaryML/baml avatar
BoundaryML/baml

BAML: A Type-Safe Language for Agent Outputs, Not Agent Logic

The programming language for agents

9,180 stars492 forksRustApache-2.0

At a glance

What is it?
BoundaryML's BAML is a Rust-based language that treats LLM outputs as typed, runtime-checkable data. It targets teams who want fewer parsing errors and stronger compile-time guarantees when calling models.
Who is it for?
Adopt BAML if your team spends too much time on brittle output parsing and wants compile-time guarantees around model responses, especially if you already use TypeScript, Python, or Go and can tolerate a nightly release cadence. Skip it if you need a stable, versioned language for agentic control flow or if your stack is Java or C#, where the README gives no concrete integration example.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What BAML Actually Solves

BAML positions itself as the programming language for agents, but the README's list of features points at a narrower problem: unreliable, untyped output from large language models. Every feature, from the Rust-like type system to runtime-persistent types and typed errors, targets the moment where an agent returns a string and your code has to turn it into a struct. The pitch is that agents make fewer mistakes when the language makes it impossible to treat an output as an untyped blob. The intended user is a developer who calls models from TypeScript, Python, Go, C#, or Java and is tired of writing validation layers by hand. It is not a general-purpose agent framework. There is no mention of planning, tool selection, or memory in the README. The scope is narrower: define a typed interface for a model call, and let BAML enforce it at compile time and runtime.

The Mechanism: Types That Survive Runtime

The core architectural claim is that types persist at runtime. In most compiled languages, types are erased or only used for static checking. BAML says there is no `any` and no casting that can silently corrupt data. That means when a model returns a JSON-like response, BAML can validate it against the declared type at runtime, not just assume the shape matches. The README also mentions typed errors that are statically analyzed. This is a meaningful difference from a plain JSON schema validator: the error type is part of the function signature, so a caller knows what can go wrong before making a call. The filesystem defines modules and namespaces, which is a deliberate design choice to avoid import path confusion. It also claims green threads and colorless concurrency like Go, though the README gives no example of how that works in practice. The type system is described as compiling faster than Go, but no benchmark supports that claim, so treat it as a marketing statement until you measure it.

Getting Started: Commands You Can Run

The README gives a short, concrete path to a first BAML project. On macOS, the install command is `brew install baml`. After that, you run `baml agent install`, which presumably sets up the runtime or a model provider, though the README does not explain what it does. Then `baml init` creates a new project scaffold. Finally, `baml ide install --code` installs the IDE extension for Visual Studio Code. The quickstart link on the homepage is the next step, but the README does not reproduce its contents. There is no mention of how to define your first function, how to call a model, or what a BAML file looks like. If you want to see syntax or a full example, you have to visit the website. That is a gap in the README, but the commands themselves are simple and should get a user to a working editor within a few minutes.

Incremental Adoption and Language Bindings

A key design decision is that you can call a BAML function from TypeScript, Python, Go, C#, and Java. That means you do not have to rewrite your entire application in BAML. You can write one function that wraps a model call, compile it, and import it from your existing codebase. This is the pragmatic path for most teams. The README says the language can run standalone or be adopted incrementally. The standalone mode is less clear: does that mean BAML has its own runtime and web server, or just that you can write a script and execute it? The README does not say. The bindings list is broad, but there is no example of the generated API surface. A Python developer would want to see whether the generated function returns a `pydantic` model or a dict. Without that detail, you are committing to an abstraction that could change between nightly releases.

Limitations and Failure Modes

The most obvious limitation is the release cadence. The latest releases are all nightly builds from early September 2026, with version numbers like `0.18.1-nightly.20260908.a`. That is a signal that the project is not at a stable 1.0. Nightly builds can break APIs, change syntax, or introduce bugs. The default branch is named `canary`, which reinforces the point: this is a project where you are expected to live on the edge. A second limitation is the lack of documentation in the README about what happens when a model output does not conform to the declared type. The README says errors are typed, but it does not say whether BAML retries, falls back, or simply throws. That matters for production systems. A third limitation is that the language is new. There is no mention of a package registry, a standard library beyond what is built in, or a migration path from earlier versions. If you adopt BAML today, you are betting that the core type system stays stable through nightly changes.

Comparison with Plain JSON Schema Validation

The closest alternative to BAML is not another language, but a validation library like `pydantic` in Python or `zod` in TypeScript. Those tools let you define a schema and validate model output, but they do not give you typed errors or compile-time analysis of what a model call can return. With BAML, the type is part of the function signature, and the runtime check is built into the call. The difference is that BAML moves the validation from a separate layer into the language itself. That can reduce boilerplate, but it also means you are learning a new language and a new toolchain. If your team already uses `pydantic` with function calling, the added value of BAML is the static error analysis and the filesystem-as-module convention. If you only need a quick validation on a few endpoints, a schema library is lighter and has a larger community. BAML is only worth the switch if you have many model calls with complex nested types and a team that wants compile-time guarantees.

Maintenance and Upgrade Considerations

The repository is written in Rust, which suggests a focus on performance and safety, but it also means that contributing to the core requires Rust knowledge. The README links to a contributing guide, but the material does not describe the contribution process. The license is Apache-2.0, which is permissive for commercial use, but you should read the full license text before shipping, especially if you plan to distribute modified versions. The release history shows a nightly cadence, so upgrades are frequent. That is a maintenance cost: you will need to track changes in the language server, the CLI, and the generated bindings. The README mentions a built-in test and eval framework, which is useful for regression testing, but it is not described in enough detail to judge whether it replaces your existing evaluation harness. Before committing, you should check the changelog for each nightly release and see how often breaking changes appear.

Who Should Adopt BAML Now

The honest answer is that BAML is for teams that feel a specific pain: model outputs that are structurally unpredictable and cause runtime crashes or silent data corruption. If you are already using TypeScript or Python and you want to define a function that returns a typed object from a model call, BAML offers a different model from bolting on a validator. The compile-time error analysis is a genuine advantage over a runtime-only schema check. However, the lack of a stable release, the canary default branch, and the thin README mean you need to be comfortable with uncertainty. The project is not for a team that needs a dependable, long-term dependency with a clear upgrade path. It is for an early adopter who is willing to file issues, read source code, and adapt to changes. Before you start, verify that the language bindings for your language are mature enough for your use case, and test a small proof of concept against your real model outputs.

Editorial conclusion

Adopt BAML if your team spends too much time on brittle output parsing and wants compile-time guarantees around model responses, especially if you already use TypeScript, Python, or Go and can tolerate a nightly release cadence. Skip it if you need a stable, versioned language for agentic control flow or if your stack is Java or C#, where the README gives no concrete integration example. Before adopting, verify that the canary branch and nightly releases match your risk tolerance, and test whether the runtime type persistence actually eliminates the parsing failures you currently see. The project is young, so check the current state of the built-in test framework and eval tooling against your own evaluation needs.

Official sources

  1. BoundaryML/baml on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes