Gleam Modules

A module is a single .gleam file. It groups related functions, types, and constants into one named unit. Modules control what is visible to other parts of your codebase, enabling clean separation of concerns and preventing unintended dependencies.

Modules Are Files


One file = One module
──────────────────────────────────────────────────
src/user.gleam        → module: user
src/order.gleam       → module: order
src/utils/format.gleam → module: utils/format

The module name is the file path relative to src/, with .gleam removed and slashes kept as separators. No registration, no declaration — the file name is the module name.

Public vs Private

// src/math.gleam

pub fn add(a: Int, b: Int) -> Int {
  a + b
}

pub fn multiply(a: Int, b: Int) -> Int {
  a * b
}

fn helper(x: Int) -> Int {   // No pub — private to this module
  x * x
}

Visibility Rules
──────────────────────────────────────────────────
pub fn    → visible anywhere (other modules, tests)
fn        → visible only inside this file
pub type  → type visible to importers
type      → type internal to this module only
pub const → constant visible to importers
const     → constant internal to this module

Public Types

// src/product.gleam

pub type Product {
  Product(
    id:    Int,
    name:  String,
    price: Float
  )
}

pub fn create(id: Int, name: String, price: Float) -> Product {
  Product(id: id, name: name, price: price)
}

fn validate_price(price: Float) -> Bool {
  price >. 0.0
}

Opaque Types

Mark a type as pub opaque to export the type name but hide its internal structure. Callers can use the type but cannot construct or destructure values directly:

// src/token.gleam

pub opaque type Token {
  Token(value: String, expires_at: Int)
}

pub fn create_token(user_id: Int) -> Token {
  Token(value: generate_value(user_id), expires_at: now() + 3600)
}

pub fn is_valid(token: Token) -> Bool {
  now() < token.expires_at
}

Opaque Type Access
──────────────────────────────────────────────────
From token.gleam:
  Can create Token(value: ..., expires_at: ...)  ✓
  Can read token.value                            ✓

From other modules:
  Can use Token as a type                         ✓
  Can call create_token, is_valid                 ✓
  CANNOT do: Token(value: ...) directly           ✗
  CANNOT do: token.value                          ✗

Module Constants

// src/config.gleam

pub const max_retries = 3
pub const default_timeout = 5000
pub const app_version = "1.0.0"
const internal_secret = "not exported"

Organizing Multiple Functions

// src/currency.gleam

pub type Currency { INR; USD; EUR; GBP }

pub fn symbol(c: Currency) -> String {
  case c { INR -> "₹"; USD -> "$"; EUR -> "€"; GBP -> "£" }
}

pub fn format_amount(amount: Float, currency: Currency) -> String {
  symbol(currency) <> float.to_string(amount)
}

pub fn convert(amount: Float, from: Currency, to: Currency) -> Float {
  let usd = to_usd(amount, from)
  from_usd(usd, to)
}

fn to_usd(amount: Float, from: Currency) -> Float {
  case from {
    INR -> amount /. 83.0
    USD -> amount
    EUR -> amount *. 1.08
    GBP -> amount *. 1.27
  }
}

fn from_usd(amount: Float, to: Currency) -> Float {
  case to {
    INR -> amount *. 83.0
    USD -> amount
    EUR -> amount /. 1.08
    GBP -> amount /. 1.27
  }
}

Private helper functions to_usd and from_usd do the detailed work. The public convert function exposes a clean interface. Callers never need to know about the internal USD conversion step.

The Module Boundary


Module Boundary Diagram
──────────────────────────────────────────────────
           currency module
┌─────────────────────────────────────┐
│  PUBLIC interface                   │
│  ┌──────────┐  ┌────────────────┐   │
│  │ symbol() │  │ format_amount()│   │
│  │ convert()│  └────────────────┘   │
│  └──────────┘                       │
│                                     │
│  PRIVATE internals                  │
│  ┌──────────┐  ┌────────────────┐   │
│  │ to_usd() │  │  from_usd()    │   │
│  └──────────┘  └────────────────┘   │
└─────────────────────────────────────┘
         ↑ other modules see only the public interface

Key Points


Module Essentials
──────────────────────────────────────────────────
1. One file = one module; name = file path from src/
2. pub exposes functions, types, and constants
3. No pub = private to this file only
4. pub opaque hides internal structure of a type
5. Modules enforce separation — callers depend only
   on the public interface, not the implementation
6. No module declaration needed — the file IS the module

Modules are Gleam's primary unit of organization. A well-designed module hides complexity behind a clear public interface, making the rest of the codebase easier to read, test, and change.

Leave a Comment

Your email address will not be published. Required fields are marked *