Gleam, the type-safe language built for the Erlang virtual machine and JavaScript runtimes, no longer writes its Erlang output as plain source code. Instead, it now generates Erlang abstract forms — an internal representation that the Erlang compiler reads directly, skipping the step of writing out human-readable code. The change landed in Gleam v1.19.0, and developer Giacomo Cavalieri did the work over the past few months.
The shift is a big deal for Gleam programmers, who now get faster builds, more accurate crash reports, and a cleaner codebase. It also closes the door on a word nobody wanted to hear: transpiler.
What the abstract form change does
Previously, Gleam compiled to Erlang source code, just like any other language targeting the BEAM. Now it produces Erlang abstract forms, a tree-like structure annotated with metadata that the compiler consumes internally. This format has a binary encoding using Erlang’s external term format, which means Gleam can feed it directly into the Erlang compiler without ever touching a file.
The result is a full build that runs faster, according to the benchmarks shown in the announcement. The difference is particularly striking for large projects, where the compiler spends real time parsing and validating code that the abstract form already contains.
Why the line numbers matter
Accurate line numbers in crash reports were a problem before this change. When a BEAM process crashes, the Erlang runtime reports the line number of the nearest function in the generated Erlang code, not the original Gleam source. That meant debugging often involved reading through a generated file to find the actual line of code that failed.
Now, the metadata stays attached to the original Gleam source. A crash report points to the correct line in the Gleam file, rather than the nearest function in the generated code. This is a quality-of-life win for anyone who has spent hours chasing a bug through generated code.
The announcement notes that this metadata could also enable full support for Gleam in debuggers like edb, though the Gleam team has not done any work on that themselves yet.
The performance gains
The benchmark data comes from José Valim’s langcompilebench project, which measures the time taken to compile 100 modules containing 100 functions each, all returning a “hello world” string. The test is simple, but it is consistent across languages, which makes it useful for comparison even if it does not reflect real-world complexity.
The chart shows a clear improvement between v1.17.0 and the newly released v1.19.0. The test is a full build from scratch, with no caching, so it measures the worst-case scenario. In normal development, where the compiler only touches changed files, the speedup would be even more noticeable.
How Gleam compares to other languages
The original langcompilebench included only Erlang, Elixir, and Gleam. The announcement extends the test to a range of popular programming languages, including Gleam compiling to JavaScript. Here is how the results stack up:
| Language | Compilation Time |
|---|---|
| Erlang | Baseline |
| Elixir | Faster than Erlang |
| Gleam (Erlang) | Faster than Elixir |
| Gleam (JavaScript) | Slower than Erlang |
The full table shows that Gleam holds its own against the languages it competes with, and the JavaScript target adds a useful comparison for developers who work in both environments. The announcement is careful to note that this is a contrived benchmark, not a definitive measure of real-world performance.
Why not bytecode?
One obvious question is why Gleam does not target BEAM bytecode directly. The answer is that bytecode is not fixed. Each new release of the virtual machine can add or remove functionality, which means a bytecode generator would have to keep pace with ongoing changes.
The announcement frames this as a resource constraint. Gleam is a community project supported by sponsorship, with a fraction of the finances available to corporate-backed or academically funded languages. The team argues that compiling to abstract forms is the most efficient use of their limited resources.
“Compiling to Erlang abstract forms is the cost-benefit sweet-spot for Gleam today.”
Elixir’s precedent
The announcement notes that Elixir itself compiles to Erlang via abstract forms. The reasoning is simple: if it is good enough for Elixir, it is good enough for Gleam.
That precedent carries weight, since Elixir compiles to abstract forms. If the Erlang maintainers themselves treat abstract forms as the standard path, it makes sense for a younger language to follow the same route.
The bigger picture
The rewrite is not just a performance patch. It also improves the quality of the code the compiler generates, according to the announcement. The Erlang code generator was one of the oldest and most stable parts of the Gleam codebase, and while it was not causing problems it was not following the team’s current standards and conventions.
The new generator is described as excellent, and the announcement argues that it raises the bar for the compiler as a whole.
What this means for developers
For a Gleam programmer, the practical takeaway is simple: builds are faster, and debugging is more accurate. The abstract form output means the compiler spends less time doing work that the BEAM compiler already handles, and the metadata means crash reports point to the correct line of code.
The announcement ends with a joke: the team never has to hear someone use the word “transpiler” as a pejorative ever again.
That is a small victory, but it is a real one. A language that compiles to abstract forms is not a transpiler in the pejorative sense — it is a compiler that speaks the BEAM’s native language directly.
Source material: “Gleam doesn't compile to Erlang source anymore,” gleam.run.
Get the Notebook.
The day's best stories and every fresh verdict, in plain English, in your inbox by seven. One email a day, no more.

