Gleam Has a Free Type-Safe Language That Runs on Erlang and JavaScript

# gleam# erlang# functional# typescript
Gleam Has a Free Type-Safe Language That Runs on Erlang and JavaScriptAlex Spinov

Gleam compiles to both Erlang BEAM and JavaScript. You get Erlang's legendary fault tolerance with a...

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!")
}
Enter fullscreen mode Exit fullscreen mode
gleam new my_app
cd my_app && gleam run
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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)
      }
    }
  })
}
Enter fullscreen mode Exit fullscreen mode

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])
  }
}
Enter fullscreen mode Exit fullscreen mode

Compile to JavaScript

# Target JavaScript instead of Erlang
gleam build --target javascript
gleam run --target javascript
Enter fullscreen mode Exit fullscreen mode

Share types and logic between your BEAM backend and JS frontend.

Why Developers Love Gleam

  1. Friendly compiler — error messages are helpful, not cryptic
  2. Fast compilation — written in Rust
  3. Great tooling — formatter, LSP, package manager built-in
  4. Interop — call any Erlang/Elixir or JavaScript library
  5. 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.