Gleam is a type-safe functional language that compiles to Erlang (BEAM) and JavaScript. It gives you Erlang's legendary fault tolerance with modern developer experience — great error messages, no null, no exceptions.
Why Gleam?
- Type-safe — catches errors at compile time, not production
- Dual target — compile to Erlang (backend) or JavaScript (frontend)
- BEAM ecosystem — use any Erlang/Elixir library
- No null, no exceptions — Result types instead
- Great DX — fast compiler, helpful errors, LSP
Install
# macOS
brew install gleam
# Linux
curl -sSfL https://gleam.run/install | sh
# Or via asdf
asdf plugin add gleam
asdf install gleam latest
Quick Start
gleam new my_app
cd my_app
gleam run
Basic Gleam
// src/my_app.gleam
import gleam/io
import gleam/string
import gleam/list
import gleam/int
pub fn main() {
// Variables are immutable
let name = "World"
io.println("Hello, " <> name <> "!")
// Pattern matching
let result = divide(10, 3)
case result {
Ok(value) -> io.println("Result: " <> int.to_string(value))
Error(msg) -> io.println("Error: " <> msg)
}
// Pipe operator
[1, 2, 3, 4, 5]
|> list.map(fn(x) { x * 2 })
|> list.filter(fn(x) { x > 4 })
|> list.each(fn(x) { io.println(int.to_string(x)) })
}
fn divide(a: Int, b: Int) -> Result(Int, String) {
case b {
0 -> Error("Division by zero")
_ -> Ok(a / b)
}
}
Web Server (Wisp Framework)
// gleam.toml — add dependencies
// gleam add wisp mist gleam_http gleam_json
import gleam/http/request.{type Request}
import gleam/http/response.{type Response}
import gleam/json
import mist
import wisp.{type Request as WispRequest, type Response as WispResponse}
pub fn main() {
let assert Ok(_) =
wisp.mist_handler(handle_request, "secret")
|> mist.new
|> mist.port(3000)
|> mist.start_http
process.sleep_forever()
}
fn handle_request(req: WispRequest) -> WispResponse {
case wisp.path_segments(req) {
[] -> wisp.ok() |> wisp.string_body("Welcome to Gleam!")
["api", "users"] -> get_users(req)
["api", "users", id] -> get_user(req, id)
_ -> wisp.not_found()
}
}
fn get_users(_req: WispRequest) -> WispResponse {
let users = json.array([
json.object([("id", json.string("1")), ("name", json.string("Alice"))]),
json.object([("id", json.string("2")), ("name", json.string("Bob"))]),
])
wisp.ok()
|> wisp.json_body(json.to_string_tree(users))
}
Custom Types (ADTs)
// No null — use Option
pub type User {
User(id: String, name: String, email: String, role: Role)
}
pub type Role {
Admin
Editor
Viewer
}
fn describe_role(role: Role) -> String {
case role {
Admin -> "Full access"
Editor -> "Can edit content"
Viewer -> "Read only"
}
}
// The compiler ensures ALL cases are handled!
Gleam for JavaScript
# Compile to JS instead of Erlang
gleam build --target javascript
gleam run --target javascript
Key Features
| Feature | Details |
|---|---|
| Type system | Static, no null, Result types |
| Targets | Erlang (BEAM) + JavaScript |
| Concurrency | OTP actors (via Erlang) |
| Package manager | Hex (shared with Erlang/Elixir) |
| Interop | Call Erlang/Elixir/JS directly |
| Compiler | Fast, helpful error messages |
Resources
Building reliable systems? I create custom data tools and integrations. Check my Apify actors or email spinov001@gmail.com.
Top comments (0)