Choosing Gleam’s Compilation Target: Erlang vs JavaScript for Your Backend
Decide whether to compile Gleam to the Erlang BEAM VM or to JavaScript by weighing concurrency, fault tolerance, and deployment constraints. A side‑by‑side table, trade‑off analysis, and a concrete HTTP endpoint test guide help you pick the right target for your service.
28 Aug 2026, 22:18 UTC

Problem: Which Gleam Target Should Your Service Use?
When you start a new Gleam project you must choose a compilation target. Gleam supports two production‑ready backends:
- Erlang (BEAM VM) – the default, mature path for long‑running services.
- JavaScript – for edge runtimes, serverless functions, or code sharing with front‑end projects.
Choosing the wrong target can lead to missed libraries, poor performance, or unnecessary maintenance overhead. This guide walks you through the constraints, options, and a validation strategy so you can make an informed decision.
Decision Constraints
Consider the following constraints that will influence the target choice:
- Deployment Environment – Is the service running on a VM, container, or serverless edge runtime?
- Statefulness & Fault Tolerance – Does the service maintain long‑lived state or require automatic restarts?
- Concurrency Model – Do you need preemptive lightweight processes or can you rely on a single‑threaded event loop?
- Library Ecosystem – Are the required Gleam packages Erlang‑only or do they support JavaScript?
- Team Skill Set – Is the team comfortable with OTP concepts or JavaScript async patterns?
Target Options in a Compact Table
| Feature | Erlang (BEAM) | JavaScript |
|---|---|---|
| Runtime | BEAM VM (OTP) | Node.js / Deno / Bun / Cloudflare Workers |
| Concurrency Model | Preemptive lightweight processes | Single‑threaded event loop with async/await |
| Fault Tolerance | Supervision trees, hot code loading | No built‑in supervision; relies on host runtime |
| Library Support | Rich OTP ecosystem (Mist, Wisp, etc.) | Limited; many Gleam packages are Erlang‑only |
| Deployment Flexibility | Containers, VPS, bare metal | Edge, serverless, CDN, or traditional server |
| FFI Complexity | Erlang externals (C, Erlang) | JavaScript externals (C, JS) |
| State Management | Processes hold state; easy to scale horizontally | State in memory or external DB; no native process isolation |
| Performance | Low‑latency, high concurrency for CPU‑bound workloads | Efficient for I/O‑bound tasks; startup time matters for serverless |
| Learning Curve | OTP concepts, supervision trees | JavaScript async/await, promises |
Trade‑Offs Explained
Fault Tolerance vs. Simplicity
BEAM’s supervision trees automatically restart crashed processes, making it ideal for services that must stay online. JavaScript lacks this, so you need to rely on the host’s process manager or implement custom retry logic.
Concurrency vs. Familiarity
Erlang processes are lightweight and preemptive, which scales well for many simultaneous connections. JavaScript’s event loop handles concurrency through async/await, but it can become a bottleneck under heavy CPU load.
Library Ecosystem
Most Gleam packages target Erlang. If your service requires a library that only supports Erlang, you’ll be forced to use the BEAM target or write a custom JavaScript binding.
Deployment Constraints
If your infrastructure is heavily invested in serverless or edge runtimes (e.g., Cloudflare Workers), JavaScript is the natural fit. For traditional server deployments where you control the VM, Erlang offers robust tooling and mature libraries.
Concrete Validation: Building an HTTP Endpoint on Both Targets
To confirm that your chosen target works in your environment, create a minimal HTTP handler and measure key metrics. The following steps assume a recent Gleam release (≥ 0.20). Replace {project_name} and {port} with your values.
- Generate the project
gleam new {project_name} cd {project_name} - Define the handler – add the following to
src/{project_name}.gleam:pub fn hello_world(_req : http.Request) : Result<http.Response, http.Error> { Ok(http.Response { status: 200, body: "Hello, world!" }) } - Configure the target – edit
gleam.tomlto settarget = "erlang"for Erlang ortarget = "javascript"for JavaScript. Keep the other target in a separate branch for comparison. - Build and run on Erlang
gleam build --target erlang # Start Mist HTTP server (a simple Erlang HTTP server) # Assuming Mist is added as a dependency # In a real project, you'd add mist to gleam.toml and expose a start function # Here we illustrate the command structure erl -pa _build/default/lib/*/ebin -s {project_name} startPermissions: Requires Erlang/OTP installed and
erlin PATH. The command runs as the current user; no special privileges are needed for local testing. - Build and run on JavaScript
gleam build --target javascript # Start a simple Node server that imports the compiled module node -e "const { hello_world } = require('./_build/default/lib/{project_name}/index.js'); const http = require('http'); http.createServer((req, res) => { const result = hello_world(req); if (result.ok) { res.writeHead(result.value.status); res.end(result.value.body); } else { res.writeHead(500); res.end('Error'); } }).listen({port});"Permissions: Requires Node.js installed. The server runs as the current user; no elevated privileges needed.
- Measure – use a load tool such as
wrkork6to hithttp://localhost:{port}/and record:- Startup time (ms)
- Memory usage (MB)
- Response latency (ms) under 100 concurrent requests
- CPU usage (percent)
Compare the results side‑by‑side. If the Erlang build shows lower latency under high concurrency, that supports choosing BEAM for a stateful service. If the JavaScript build has a faster cold start and lower memory footprint, that favors a serverless or edge deployment.
Practical Checklist Before Committing
- Pin the Gleam version in
gleam.tomland verifygleam buildsucceeds on both targets. - Audit each dependency’s
gleam.tomlfortarget = "erlang"ortarget = "javascript"support. - Write FFI externals only once if you only target one platform; otherwise duplicate them for each target.
- Run the validation test in a staging environment that mirrors production.
- Document the chosen target and rationale in the project README.
By following this decision guide and validation workflow, you can confidently select the Gleam target that aligns with your service’s operational needs and deployment constraints.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.