Model or dataset
BoundaryML/baml avatar
BoundaryML/baml

BAML: a typed language for LLM functions, installed with brew install baml

The programming language for agents

9,360 stars494 forksRustApache-2.0

At a glance

What is it?
BAML compiles a TypeScript-shaped DSL into clients for Python, TypeScript, Go, C#, Java and more, so LLM calls return typed values instead of raw strings. The README is strong on the pitch and thin on the runtime details.
Who is it for?
Adopt BAML if you want LLM call sites to carry static types across several host languages and you are willing to keep the .baml sources and the generated clients in sync. Skip it if you need documented rollback, a stable non-nightly release cadence, or a runtime that the README explains in detail, because it does not.
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 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem BAML targets: untyped strings at every LLM call site

Most applications that call a model end up with the same shape: a prompt string, a JSON parse, and a hand-written validator that drifts from the prompt. BAML's answer is to move the prompt and the expected shape into a separate language. The README describes it as "the programming language for agents" and says it "looks like TypeScript, but every feature is built so agents make fewer mistakes." The claim that matters is narrower: types persist at runtime, and there is "no `any` nor casting dangerously to any type." That is a statement about generated code, not about the model. If your Python service currently does `json.loads(response)` and then hopes the keys are right, BAML is aimed at exactly that seam. It is for teams that already ship LLM features in a typed host language and are tired of the parse-and-pray step. It is not for someone who wants a prompt playground or a no-code agent builder.

How BAML works: a DSL, a compiler, and generated clients

The architecture visible in the repository is a compiler plus per-language bindings. The top level holds `baml_language/`, `engine/`, `languages/`, `typescript/`, `typescript2/`, `baml-cli/` and `integ-tests/`, with a `go.mod` declaring `module github.com/boundaryml/baml` and Go 1.24.0. That layout says the core is written in Rust (the repository's primary language) and that host-language packages are generated or maintained alongside it. The README states that the filesystem describes modules and namespaces, that errors are typed and statically analyzed, and that BAML can "be run standalone or adopt incrementally (you can call a BAML function from TS, Py, Go, C#, Java, etc)." Incremental adoption is the important part: you do not rewrite the application, you add a BAML file and call into it. The README also claims green threads and colorless concurrency like Go, and a built-in test and eval framework. Those are claims about the language, not benchmarks, and the README gives no numbers for any of them.

Installing BAML and running baml init

The README gives one installation path, Homebrew, followed by three subcommands. Run them in order.

bash
brew install baml
baml agent install
baml init
baml ide install --code

The first line installs the CLI. `baml agent install` is the README's own step for the agent tooling. `baml init` is what creates the project scaffold, so run it inside the directory where you want the BAML sources to live. The last line wires the editor integration for VS Code, which matters because the language server is a separate package in this monorepo (`@baml/language-server` appears in the root package.json dev scripts). After these four commands the README points to the quickstart at boundaryml.com/quickstart rather than documenting the generated files itself. That is the first real gap: the repository does not tell you what `baml init` writes, what the default model provider is, or which environment variable holds an API key. You will learn that from the website or by reading the scaffold. The README also does not document an uninstall or a rollback path for the generated clients.

Where BAML gets in the way

The release list is the clearest limitation. The three most recent releases are all nightly builds of `baml-language-0.18.1`, dated 2026-09-08 and 2026-09-09. Nothing in the release history shows a stable, non-nightly 0.18.1. If your team pins dependencies and requires a tagged stable release before upgrading, that cadence is a real constraint, and the README does not describe a support policy for nightlies. The second limitation is documentation depth. The README is a feature list, not a reference: it does not document the grammar, the stdlib, the eval framework's API, or the failure modes of the compiler. The third is the incremental-adoption claim itself. Once a BAML function is called from Python and Go, you own two generated clients, and the README does not describe how regeneration is triggered in CI. A team that cannot keep generated code in the build pipeline will find that the type safety stops at the repository boundary. Finally, if your task is a single model call with a fixed string response, the DSL, the CLI and the generated clients are more machinery than the problem needs.

BAML compared with writing the prompt in your host language

The realistic alternative is not another DSL. It is doing the work in Python or TypeScript with a schema library: define a Pydantic model or a Zod schema, ask the provider for structured output, and validate. That approach keeps one language, one build, and one dependency graph. The difference is where the type lives. With a schema library, the prompt text and the schema are separate artifacts that a developer must keep aligned, and the schema is a runtime check. BAML puts the prompt and the type in the same file and compiles that file into a client, so the type exists before the process starts and is shared across languages. The trade is that you now maintain a second language and a code generator. If your application is Python-only and you already validate with Pydantic, the schema-library route is less machinery for the same runtime guarantee. BAML earns its place when several host languages call the same prompts and you want one definition of the shape.

Licence, releases and what maintenance costs

The repository is Apache-2.0, which permits commercial use and modification and includes a patent grant. Note that the licence covers the repository; the generated clients and any hosted service at boundaryml.com are separate questions that the README does not address, and nothing here is legal advice. The last push was on 2026-09-09, so the project is being worked on, and the release tags show nightlies landing within a day of each other. For an adopter, that means the upgrade cost is not a yearly event. You should expect to regenerate clients and re-run your evals whenever you move the version, and the repository's `CHANGELOG.md` and `cliff.toml` are the files that describe how those notes are produced. There is also a `TELEMETRY.md` at the top level, which is the file to read before you decide what the CLI and language server are allowed to send. The README does not state whether telemetry is on by default.

Editorial conclusion

Adopt BAML if you want LLM call sites to carry static types across several host languages and you are willing to keep the .baml sources and the generated clients in sync. Skip it if you need documented rollback, a stable non-nightly release cadence, or a runtime that the README explains in detail, because it does not. Before committing, run the four install commands from the README on a scratch machine and check what the generated client looks like in your language, then read TELEMETRY.md, which is the only top-level file that speaks to what leaves your process.

Frequently asked questions

How do I install BAML and start a new project?

The README gives four commands: brew install baml, then baml agent install, baml init, and baml ide install --code. The last one sets up the editor integration. The README then points to the quickstart on boundaryml.com rather than describing the generated files.

Can I call BAML functions from Python or TypeScript?

Yes. The README states that BAML can be run standalone or adopted incrementally, and that you can call a BAML function from TS, Py, Go, C#, Java and other languages. The repository keeps separate language packages and an integ-tests directory alongside the Rust core.

Does BAML have a stable release or only nightly builds?

The three most recent releases listed are all nightly builds of baml-language-0.18.1, dated 2026-09-08 and 2026-09-09. No stable non-nightly release appears in the release history, and the README does not describe a support policy for nightlies.

Official sources

  1. BoundaryML/baml on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/boundaryml-baml.svg)](https://hysenlabs.com/projects/boundaryml-baml)