Mojo Data Types
Every piece of data in a Mojo program has a type. The type tells Mojo how many bytes to reserve in memory, what operations are valid, and how to interpret the stored bits. Choosing the right type keeps your programs accurate and fast.
Why Types Matter
Without types: With types: ┌─────────────────┐ ┌───────────────────────┐ │ 10110010 │ │ Int8: 10110010 = -78 │ │ (just bits) │ │ UInt8: 10110010 =178 │ │ What does │ │ (meaning is clear) │ │ this mean? │ └───────────────────────┘ └─────────────────┘
The same pattern of bits means different things depending on the type. Mojo uses types to ensure operations produce the result you actually intend.
Integer Types
An integer stores a whole number — no decimal point. Mojo provides several integer types that differ in size and whether they allow negative values.
Signed Integers
Signed integers hold both negative and positive values.
Type | Bits | Range -------|------|------------------------------------ Int8 | 8 | -128 to 127 Int16 | 16 | -32,768 to 32,767 Int32 | 32 | -2,147,483,648 to 2,147,483,647 Int64 | 64 | -9.2 × 10¹⁸ to 9.2 × 10¹⁸ Int | 64* | Same as Int64 on 64-bit systems
fn main():
var small: Int8 = 100
var medium: Int32 = 1_000_000
var large: Int64 = 9_000_000_000
print(small, medium, large)
The underscore in 1_000_000 is a visual separator — Mojo ignores it. It makes large numbers easier to read, the same way commas separate digits in everyday writing.
Unsigned Integers
Unsigned integers hold only zero and positive values. Because they skip the negative half, they can store numbers twice as large in the same number of bits.
Type | Bits | Range -------|------|------------------------ UInt8 | 8 | 0 to 255 UInt16 | 16 | 0 to 65,535 UInt32 | 32 | 0 to 4,294,967,295 UInt64 | 64 | 0 to 1.8 × 10¹⁹
fn main():
var pixel_value: UInt8 = 255 # Max brightness
var port_number: UInt16 = 8080
print(pixel_value, port_number)
Floating-Point Types
Floating-point types store numbers with decimal points. They represent a vast range of values by trading off some precision.
Type | Bits | Decimal Precision | Example Use ----------|------|-------------------|------------------ Float16 | 16 | ~3 digits | AI model weights BFloat16 | 16 | ~3 digits | AI training Float32 | 32 | ~7 digits | Graphics, physics Float64 | 64 | ~15 digits | Science, finance
fn main():
var temperature: Float32 = 98.6
var pi: Float64 = 3.141592653589793
print(temperature)
print(pi)
Float16 and AI Workloads
AI models store billions of numbers. Using Float32 for all of them consumes enormous memory and bandwidth. Float16 and BFloat16 cut that in half with a small precision trade-off that AI training can tolerate. Mojo makes these types first-class citizens precisely because of their importance in AI development.
The Bool Type
A boolean holds exactly one of two values: True or False. Booleans drive decisions in your program.
fn main():
var is_logged_in: Bool = True
var has_error: Bool = False
print(is_logged_in) # True
print(has_error) # False
Comparison operations produce booleans:
fn main():
var x = 10
var result: Bool = x > 5
print(result) # True
The String Type
A string stores a sequence of characters — letters, digits, spaces, punctuation, emoji. Enclose string literals in double quotes.
fn main():
var greeting: String = "Hello, Mojo!"
var city = "Tokyo"
print(greeting)
print("City:", city)
String Length
fn main():
var word: String = "Mojo"
print(len(word)) # 4
The SIMD Type (Preview)
SIMD stands for Single Instruction, Multiple Data. Instead of holding one number, a SIMD value holds a fixed-size collection of numbers that the CPU can process all at once. This is one of Mojo's most powerful performance features.
Scalar approach (one at a time): Add 1+1, then 2+2, then 3+3, then 4+4 → 4 CPU instructions SIMD approach (all at once): [1,2,3,4] + [1,2,3,4] = [2,4,6,8] → 1 CPU instruction
fn main():
var v = SIMD[DType.float32, 4](1.0, 2.0, 3.0, 4.0)
var w = SIMD[DType.float32, 4](10.0, 20.0, 30.0, 40.0)
var result = v + w
print(result) # [11.0, 22.0, 33.0, 44.0]
You will explore SIMD in depth in a dedicated topic later. For now, remember that it exists and it is one reason Mojo outperforms Python by orders of magnitude on numerical code.
Type Conversion
You cannot freely mix types in arithmetic. Mojo requires explicit conversion to prevent silent errors.
fn main():
var whole: Int = 7
var fraction: Float64 = 2.5
# This line causes a compile error:
# var result = whole + fraction
# Convert Int to Float64 first:
var result = Float64(whole) + fraction
print(result) # 9.5
Type Conversion Diagram: Int ──── Float64(x) ────→ Float64 Float64 ─ Int(x) ────────→ Int (truncates decimal) Int ──── String(x) ──────→ String String ── Int(x) ────────→ Int (if string is a number)
Choosing the Right Type
Situation | Best Type --------------------------------|---------- Counting items (loop index) | Int Pixel color channel (0–255) | UInt8 GPS latitude / longitude | Float64 Age of a person | UInt8 or Int Flag (yes/no, on/off) | Bool Name or description | String AI weight in neural network | Float16 or BFloat16 Batch of sensor readings | SIMD[DType.float32, N]
Key Takeaways
Mojo provides integer types in four sizes (8, 16, 32, 64 bits), both signed and unsigned. Floating-point types exist in three precisions with Float64 as the general-purpose choice and Float16 optimized for AI. The Bool type holds true/false values. String holds text. SIMD types pack multiple numbers into one value for parallel computation. Always convert between incompatible types explicitly — Mojo will not do it silently.
