Toolchain
One command, bea, does for a Bea project what gleam does for a Gleam project, plus a few things of its own. Behind it, Gleam does the type checking and generates Erlang or JavaScript.
Install
Each release comes with a standalone bea for Linux (x86-64), for now the only platform with a binary. It carries its own Erlang runtime, so the binary itself needs nothing else installed.
Building projects needs Gleam, and Erlang/OTP for the Erlang target or Node for JavaScript: bea hands the generated Gleam to them.
$ mkdir -p ~/.local/bin
$ curl -fsSL -o ~/.local/bin/bea \
https://github.com/the-bea-project/bea/releases/latest/download/bea-linux-amd64
$ chmod +x ~/.local/bin/bea
$ bea --version
bea 0.3.0| To run bea | To build a project | |
|---|---|---|
| Linux, x86-64 | the release binary | the release binary |
| Gleam | no | yes: Bea compiles to Gleam, Gleam does the rest |
| Erlang/OTP | no, it's built in | for the Erlang target (the default) |
| Node, Bun or Deno | no | for --target javascript |
| Other platforms | no binary yet | build Bea from source (docs/self-hosting.md) |
Commands
Flags Bea doesn't know are passed on to Gleam, and everything Gleam prints is rewritten to point at your .bea files.
| Command | What it does |
|---|---|
bea new NAME | Create a project |
bea add PKG... | Add Hex dependencies (--dev for dev ones), e.g. bea add lustre gleam_json |
bea remove, update, deps | Remove, update and inspect dependencies |
bea check | Type check |
bea build | Build (--target javascript, --warnings-as-errors, …) |
bea run | Run a module's main, from the project root: the project's, another module's (-m) or a Gleam tool's |
bea test | Run the tests: the main of test/<package>_test.gleam (gleeunit or any runner) |
bea format | Format .bea files (--check, --imports to organise imports) |
bea shell | An interactive Bea shell in the project |
bea transpile FILE.bea | Print the Gleam a file becomes |
bea transpile --out DIR | Write the project out as a plain Gleam project, to leave Bea |
bea pack | Package the project into one standalone executable, with gleepack |
bea export | Gleam's exports: erlang-shipment, escript, … |
bea publish, bea hex | Publish to Hex, as the generated Gleam package |
bea lsp | The language server, for editors |
bea clean | Delete .beabuild/ |
How a build works
Bea never generates Erlang or JavaScript itself. It turns your .bea files into a Gleam project, lets Gleam build it, and translates what Gleam says back to your source.
- Sync.
beareadsbea.tomland writes the Gleam project in.beabuild/:gleam.toml, every changed.beafile compiled to a.gleamfile with a source map, and Gleam modules, FFI files and tests copied as they are. - Compile. Each
.beafile goes through Bea's compiler, written in Bea: the stages below. Bea's own syntax errors are reported here. - Gleam.
gleam build(orcheck,run,test) runs on.beabuild/: dependencies from Hex, type checking, then Erlang or JavaScript. - Map back. Gleam's errors and warnings,
echooutput and stack traces come back through the source maps, pointing at your.bealines with the Bea code in the snippet.
.bea ──lexer──▶ tokens ──parser──▶ AST ──deriving──▶ AST ──lower──▶ AST ──codegen──▶ .gleam + source map
(spans, (Pratt, (@derive (cond, ?, else, (pretty printer
comments) recovery) → functions, returns, with marks)
Type.f → f) clauses)| Stage | What it does |
|---|---|
bea/lexer | Tokens with exact spans, comments kept, string interpolation |
bea/parser | Recursive descent with Gleam's precedence table, and error recovery per definition |
bea/deriving | @derive(m) on a record → ordinary functions calling the deriver module m |
bea/associated | Type.name → the function <type>_<name> it names |
bea/lower | cond, else guards, ?, early returns and multi-clause functions → Gleam's constructs |
bea/codegen | Prints Gleam: scope-aware imports, let or let assert, positions for the source map |
bea/formatter | bea format, which checks its output parses back to the same program |
A project
| Path | What it is |
|---|---|
bea.toml | The project: name, version, target, dependencies. Like gleam.toml, plus [tools.gleepack] |
manifest.toml | Locked dependency versions |
src/*.bea | Bea modules |
src/*.gleam, *.erl, *.mjs | Gleam modules and FFI files, next to the Bea ones |
test/*.gleam | Tests, in Gleam, run by bea test |
.beabuild/ | The generated Gleam project (don't commit it) |
build/ | Where bea pack puts executables |
Testing and shipping
bea test
Runs the main of test/<package>_test.gleam, built with the rest of the project, from the project root, so tests can read files relative to it. Tests are Gleam and call Bea modules like any other. The testing lesson has a complete example.
bea pack
Packages the project into one executable with gleepack: the compiled project, its dependencies and a small Erlang runtime in a single file that runs on machines without Erlang. It suits CLIs, TUIs and dev tools on the Erlang target. The bea binary itself is made this way, by bea pack in Bea's own repository.
gleepack is the gleepack on your PATH (from its releases), the one BEA_GLEEPACK names, or a dev dependency of the project.
$ bea test
$ bea pack # build/<package>
$ bea pack -o dist/app # somewhere else
$ bea pack -m app/cli # another main
$ bea pack -t amd64-linux-otp-29.1.1 \
-t aarch64-macos-otp-29.1.1[dev_dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
gleepack = { git = "https://github.com/yoshi-monster/gleepack.git", ref = "main" }
[tools.gleepack]
output = "dist/app"
module = "app/cli"