Choosing Between Gleam Native and JavaScript Compilation Targets
Decide whether to compile Gleam to a standalone BEAM executable or JavaScript based on deployment platform, binary size, and system interoperability needs.
31 Mar 2026, 09:40 UTC

You need to decide how to compile a Gleam program: to an Erlang/BEAM executable that runs on a server or command line, or to JavaScript that runs in a browser or Node.js. The wrong choice can force a rewrite later because switching targets changes build configuration and may require rewriting code that touches platform-specific APIs.
The useful takeaway is to choose the Erlang/BEAM target for command-line tools, background workers, and services that need direct system access. Choose the JavaScript target for browser front-ends or projects that must integrate with an existing JavaScript package. Benchmark the critical path before committing to either target.
The Decision and Constraints
Gleam compiles source code to one of two supported targets. The BEAM is the Erlang virtual machine that executes Gleam code compiled to the Erlang target. A native build in this context means a standalone executable or BEAM bytecode package produced by the Erlang target, not a machine-code binary compiled from Gleam directly.
Constraints to weigh before choosing:
- Deployment platform: server, CLI, browser, or Node.js
- Binary or bundle size: bandwidth, storage, and cold-start time
- Interoperability: Erlang/Elixir libraries versus JavaScript packages
- System access: files, processes, sockets, and native APIs
- Toolchain stability: maturity of the target in your installed Gleam version
Supported Targets at a Glance
| Target | Output | Typical use | Main constraint |
|---|---|---|---|
| Erlang/BEAM | Standalone executable or BEAM bytecode | Servers, CLIs, background workers | Built for the target OS and processor architecture |
| JavaScript | JS bundle with source map | Web browsers, Node.js | Experimental output; limited direct system access |
Trade-offs
Erlang/BEAM target
Advantages: the BEAM VM provides lightweight processes and multi-core concurrency, and the resulting executable can call Erlang libraries and operating-system APIs directly. Startup is usually fast because there is no JavaScript engine warm-up.
Disadvantages: the executable or package is typically several megabytes, which matters for constrained environments. You must build on the same OS and architecture as the deployment target, or the executable will not run. Debugging may require external symbols or a separate debug build.
JavaScript target
Advantages: output runs anywhere JavaScript runs, integrates with npm packages, and source maps are generated automatically to simplify browser debugging. Bundles are often smaller than BEAM executables, which helps browser delivery.
Disadvantages: JavaScript output is still experimental in many Gleam releases and may change across minor versions. Some Gleam constructs, especially those relying on Erlang interop, may not translate correctly. Startup overhead and concurrency behavior depend on the JavaScript engine, which can be less deterministic than the BEAM scheduler.
Version and Feature Assumptions
Gleam documentation describes the Erlang target as mature and the JavaScript target as experimental. Because this can change between minor releases, verify your installed version before relying on either target for production. Run gleam --version and inspect gleam build --help to confirm which targets your toolchain accepts.
Concrete Validation: Compile Hello World to Both Targets
Run these commands in the project directory as an ordinary user. No root or administrator permissions are required. Replace <project-name> with your project identifier.
- Create a new project:
gleam new <project-name>- Enter the project:
cd <project-name>- Edit
src/<project-name>.gleamso the main function prints a message, for example: pub fn main() {io.println("Hello from Gleam")}- Build for Erlang/BEAM:
gleam build --target erlang
Expected check: an executable appears under the dev/erlang/ directory. Running it should print Hello from Gleam. Risk: an executable built on Apple Silicon will not run on an x86_64 server without a matching build host or cross-compilation setup.
- Build for JavaScript:
gleam build --target javascript
Expected check: the dev/javascript/ directory contains a JavaScript bundle and a corresponding .map source-map file. Inspect the map file to confirm source mapping is present. Risk: JavaScript output may omit or alter Gleam constructs that depend on Erlang-specific behavior.
Diagnostic Decision Checklist
- Deploying a CLI or long-running service? Choose Erlang/BEAM.
- Deploying to a browser? Choose JavaScript.
- Need direct file-system or process access? Choose Erlang/BEAM.
- Must integrate with an existing React or Node.js library? Choose JavaScript.
- Uncertain about performance? Build both targets from the same source and measure startup time and memory use on a representative workload.
Limitations and Verification
This is a conservative draft. The commands and directory layouts are illustrative and have not been executed against a live Gleam toolchain. Verify them with your installed version before using them in a pipeline.
Practical verification steps:
- Run
gleam --versionand record the version. - Run
gleam build --target erlangandgleam build --target javascriptfrom the same source tree. - Run each output and confirm it prints the expected message.
- Inspect the JavaScript output directory for a source-map file.
- Compare file sizes and startup time for the two outputs.
Rollback is simple because these commands only create files inside the project directory. Delete the dev/ directory to remove build artifacts; no system-wide state is changed.
Recommended Default
Start with Erlang/BEAM for backend tooling, services, and CLIs. Start with JavaScript for browser front-ends. If a critical code path is performance-sensitive, benchmark both targets on the actual deployment hardware before making the final decision.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.