Gleam Variables
Variables in Gleam store values so you can use them later in your program. Gleam handles variables differently from most languages — understanding the rules saves you from confusion and common mistakes.
Creating a Variable with let
Use the let keyword to create a variable:
let age = 25
let name = "Riya"
let price = 9.99
let is_active = TrueGleam reads the value on the right side and stores it under the name on the left. You use that name later to access the value.
Variable Assignment Diagram
──────────────────────────────────────────────
let age = 25
│ │ │
│ │ └── value (Int)
│ └────────── variable name
└─────────────── keyword
Gleam Infers Types Automatically
You do not write the type yourself — Gleam figures it out from the value you assign.
let score = 100 // Gleam knows: score is an Int
let label = "gold" // Gleam knows: label is a String
let ratio = 0.75 // Gleam knows: ratio is a Float
let done = False // Gleam knows: done is a BoolYou can write the type explicitly if you want to be extra clear:
let score: Int = 100
let label: String = "gold"Both styles are valid. Gleam uses explicit types in function signatures where clarity matters most.
Variables Are Immutable
Once you bind a name to a value, you cannot change that value. Gleam variables are immutable — they never change after creation.
Think of a Variable Like a Label on a Box
──────────────────────────────────────────────
let score = 10
┌──────────┐
│ 10 │ ← score
└──────────┘
You CANNOT reach into the box and change 10 to 20.
The box is sealed.
This might sound limiting, but it prevents an entire class of bugs. When a value never changes, you always know exactly what it is — no matter how large or complex your program grows.
Shadowing: Creating a New Variable with the Same Name
While you cannot mutate a variable, you can create a new variable with the same name. This is called shadowing.
let points = 50
let points = points + 10 // a new binding, not a mutation
// points is now 60
Shadowing Diagram
──────────────────────────────────────────────────
Step 1: let points = 50
┌──────┐
│ 50 │ ← points
└──────┘
Step 2: let points = points + 10
┌──────┐ ┌──────┐
│ 50 │ │ 60 │ ← points (new binding)
└──────┘ └──────┘
↑
old value, read once, then forgotten
The old points (50) is no longer reachable. The new points (60) replaces it in scope. Gleam does not mutate the original — it creates a fresh binding.
Variables Exist Inside Their Scope
A variable exists only within the block of code where you defined it. When the block ends, the variable disappears.
pub fn main() {
let x = 5
{
let y = 10 // y exists only inside these braces
let sum = x + y
io.debug(sum) // prints 15
}
// y does not exist here — using y here causes a compile error
io.debug(x) // prints 5 — x still exists
}
Scope Diagram
──────────────────────────────────────────────
main() scope
├── x = 5 (lives for the whole function)
└── inner block scope
├── y = 10 (disappears when block ends)
└── sum = 15 (disappears when block ends)
Using Variables in Expressions
Variables can appear anywhere a value is expected:
let base = 100
let tax_rate = 0.18
let tax = base * tax_rate // 18.0
let total = base + tax // 118.0Gleam evaluates each expression from right to left, stores the result in the variable, and makes it available for the next line.
Naming Rules for Variables
Naming Rules
──────────────────────────────────────────────────
Rule │ Example
─────────────────────────┼────────────────────────
Start with lowercase │ age, total_price
Use snake_case │ first_name, order_id
Letters, digits, _ │ count_1, page_size
No spaces or dashes │ ✗ first-name, first name
No starting digit │ ✗ 1count
Good variable names describe the value they hold. A name like x works in a small example but becomes confusing in a large program. Prefer descriptive names like user_count or order_total.
The Discard Variable
Sometimes a function returns a value you do not need. Gleam requires you to acknowledge that value — you cannot just ignore it silently. Use the underscore prefix to tell Gleam you intentionally discard the value:
let _unused = some_function() // Gleam will not warn about this
Using a plain underscore _ alone also works:
let _ = some_function()Constants
Use const for values that belong to the module level and never change:
const max_retries = 3
const app_name = "MyShop"
const pi = 3.14159
const vs let
──────────────────────────────────────────────────
Feature │ const │ let
────────────┼────────────────┼────────────────────
Scope │ Module level │ Function level
Usage │ Config values │ Local computation
Evaluated │ At compile time│ At runtime
Constants appear at the top of a file, outside functions. They represent fixed configuration — tax rates, limits, application names — values that every function in the module might need.
Practical Example
import gleam/io
const discount_rate = 0.10
pub fn calculate_total(price: Float, quantity: Int) -> Float {
let subtotal = price *. int.to_float(quantity)
let discount = subtotal *. discount_rate
let total = subtotal -. discount
total
}
pub fn main() {
let total = calculate_total(200.0, 3)
io.debug(total) // prints 540.0
}Each let binding breaks the calculation into a readable step. Anyone reading this code understands the math without needing a comment.
Summary
Key Rules for Gleam Variables
──────────────────────────────────────────────────
1. Use "let" to bind a value to a name
2. Gleam infers the type — you rarely write it
3. Variables are immutable — values never change
4. Shadowing creates a new binding, not a mutation
5. Variables live only within their scope block
6. Use "const" for module-level fixed values
7. Use _ prefix to discard unused variables
Immutability is one of Gleam's strengths. Programs become easier to read, test, and maintain when values stay fixed after creation.
