Claude Code for Gleam Language — Workflow Guide

Written by Michael Lip · Solo founder of Zovo · $400K+ on Upwork · 100% JSS Join 50+ builders · More at zovo.one

The Setup

You are writing code in Gleam, the type-safe language that compiles to Erlang (BEAM) and JavaScript. Gleam combines functional programming with friendly syntax and targets the battle-tested BEAM platform. Claude Code can generate Gleam code, but it writes Elixir, Erlang, or generic ML-style syntax that does not compile.

What Claude Code Gets Wrong By Default

  1. Writes Elixir syntax. Claude generates def function(arg) do ... end Elixir blocks. Gleam uses pub fn function(arg: Type) -> ReturnType { ... } with Rust-like syntax and curly braces.

  2. Uses dynamic typing patterns. Claude writes code without type annotations. Gleam is statically typed — every function signature needs explicit types, and the compiler rejects untyped code.

  3. Uses OOP patterns. Claude creates classes and methods. Gleam is purely functional — use modules, functions, and custom types (discriminated unions). No classes, no mutable state, no methods.

  4. Ignores the Result type for error handling. Claude uses try/catch or raises exceptions. Gleam uses Result(Ok, Error) types and use expressions (like Rust’s ? operator) for error propagation.

The CLAUDE.md Configuration

# Gleam Language Project

## Language
- Language: Gleam (compiles to Erlang BEAM or JavaScript)
- Build: gleam build, gleam run
- Package manager: gleam add <package>
- Target: erlang (default) or javascript

## Gleam Rules
- Functions: pub fn name(arg: Type) -> Return { }
- Types: type MyType { Variant1(field: String) | Variant2 }
- Pattern matching: case value { Variant1(f) -> ... }
- Error handling: Result(value, error) with use keyword
- Pipes: value |> function1 |> function2
- No mutable variables — use let for binding
- Modules: one file = one module, public with pub keyword
- String interpolation: not supported, use string.concat()

## Conventions
- Source in src/ directory
- Tests in test/ directory
- gleam.toml for project configuration
- Use Result type for all fallible operations
- Pattern match exhaustively — compiler enforces it
- Use pipe operator |> for data transformations
- Custom types for domain modeling (no classes)

Workflow Example

You want to create a simple HTTP API with Gleam. Prompt Claude Code:

“Create a Gleam function that parses a JSON user payload, validates the email field, and returns either a User type on success or a validation error. Use the Result type for error handling.”

Claude Code should define a User custom type, a ValidationError type, write a parse function returning Result(User, ValidationError), use use expressions for chaining fallible operations, and pattern match on the result.

Common Pitfalls

  1. No string interpolation. Claude writes "Hello #{name}" or f"Hello {name}". Gleam does not have string interpolation. Use string.concat(["Hello ", name]) or the string_builder module for efficient concatenation.

  2. Forgetting exhaustive pattern matches. Claude writes partial case expressions. The Gleam compiler requires exhaustive matching — every variant must be handled, or the code does not compile.

  3. Erlang interop assumptions. Claude calls Erlang functions directly without FFI declarations. Gleam requires @external(erlang, "module", "function") attributes to call Erlang functions, with proper type annotations at the boundary.