Gleam compiles to both Erlang BEAM and JavaScript. You get Erlang's legendary fault tolerance with a modern, friendly type system.
Why Gleam
- Type-safe — catches bugs at compile time (unlike Elixir/Erlang)
- Runs on BEAM — battle-tested runtime (WhatsApp, Discord)
- Compiles to JS — share code between server and browser
- No null — uses Result type instead
- Immutable — all data is immutable by default
- Beautiful syntax — inspired by Rust, Elm, and Go
Hello World
import gleam/io
pub fn main() {
io.println("Hello, Gleam!")
}
gleam new my_app
cd my_app && gleam run
Type System
// Custom types (like Rust enums)
pub type Shape {
Circle(radius: Float)
Rectangle(width: Float, height: Float)
Triangle(base: Float, height: Float)
}
pub fn area(shape: Shape) -> Float {
case shape {
Circle(r) -> 3.14159 *. r *. r
Rectangle(w, h) -> w *. h
Triangle(b, h) -> 0.5 *. b *. h
}
}
// Compiler ensures ALL cases are handled
Error Handling (No Exceptions)
import gleam/result
pub type AppError {
NotFound
Unauthorized
DatabaseError(String)
}
pub fn get_user(id: Int) -> Result(User, AppError) {
case db.find_user(id) {
Ok(user) -> Ok(user)
Error(_) -> Error(NotFound)
}
}
// Chain operations
pub fn get_user_email(id: Int) -> Result(String, AppError) {
use user <- result.try(get_user(id))
use profile <- result.try(get_profile(user))
Ok(profile.email)
}
The use keyword makes error handling clean — no nested case statements.
Concurrency (OTP)
import gleam/erlang/process
import gleam/otp/actor
pub type Message {
Increment
GetCount(process.Subject(Int))
}
pub fn counter() {
actor.start(0, fn(message, count) {
case message {
Increment -> actor.continue(count + 1)
GetCount(reply_to) -> {
process.send(reply_to, count)
actor.continue(count)
}
}
})
}
Actors, supervisors, fault tolerance — all the OTP power.
Web Server (Wisp)
import wisp
import gleam/http
pub fn handle_request(req: wisp.Request) -> wisp.Response {
case wisp.path_segments(req) {
[] -> wisp.ok() |> wisp.string_body("Hello!")
["users", id] -> get_user_handler(req, id)
_ -> wisp.not_found()
}
}
fn get_user_handler(req: wisp.Request, id: String) -> wisp.Response {
case req.method {
http.Get -> {
// Fetch and return user
wisp.ok() |> wisp.json_body(user_json)
}
_ -> wisp.method_not_allowed([http.Get])
}
}
Compile to JavaScript
# Target JavaScript instead of Erlang
gleam build --target javascript
gleam run --target javascript
Share types and logic between your BEAM backend and JS frontend.
Why Developers Love Gleam
- Friendly compiler — error messages are helpful, not cryptic
- Fast compilation — written in Rust
- Great tooling — formatter, LSP, package manager built-in
- Interop — call any Erlang/Elixir or JavaScript library
- Growing ecosystem — 1,500+ packages on Hex
Interested in robust backend systems? I build developer tools and data infrastructure. Email spinov001@gmail.com or check my Apify tools.
Top comments (0)