Mojo
Python syntax, systems speed, built for AI.
Mojo is a language from Modular that looks like Python but compiles to fast native code for CPUs and GPUs. It was created by Chris Lattner (who also created LLVM and Swift) to write AI kernels and models without switching between Python and C++ or CUDA.
Why learn Mojo?
Mojo targets the exact problem AI engineers face: Python is easy but slow, while CUDA and C++ are fast but hard.
- Familiar: Python-like syntax with types where you need speed.
- Fast: SIMD, parallelism and GPU kernels written in one language.
- AI-native: powers Modular's MAX inference engine and custom GPU kernels.
Set up and run your first program
Install the Pixi package manager, then create a project with Mojo. Mojo runs on Linux and macOS (Apple silicon).
curl -fsSL https://pixi.sh/install.sh | sh
pixi init hello-mojo -c https://conda.modular.com/max-nightly/ -c conda-forge
cd hello-mojo && pixi add mojo
pixi run mojo hello.mojofn main():
var name = "Ada"
print("Hello, AI! Welcome to Mojo,", name + ".")Variables and types
Declare variables with var, optionally with a type. Types such as Int, Float64 and String let the compiler produce fast code.
fn main():
var layers: Int = 32
var lr: Float64 = 3e-4
var model: String = "llama3.1"
var params = 8.03e9
print(model, layers, lr)
print("FP16 GB:", params * 2 / 1e9)fn and def
fn functions are strict: arguments need types and errors must be declared with raises. def functions behave more like Python.
fn params(layers: Int, width: Int = 4096) -> Int:
return 12 * layers * width * width
def greet(name):
return "Hi " + String(name)
fn main() raises:
print(params(32))
print(greet("Mojo"))Control flow and collections
Loops and conditions look like Python. List and Dict come from the standard library.
from collections import Dict
fn main() raises:
var gpus = List[String]("H100", "H200", "B200")
for g in gpus:
print(g)
var vram = Dict[String, Int]()
vram["H100"] = 80
vram["H200"] = 141
for e in vram.items():
if e.value > 100:
print(e.key, "has", e.value, "GB")Structs and traits
Structs are like classes but fixed at compile time, which makes them fast. Traits describe shared behaviour.
@fieldwise_init
struct Gpu(Copyable, Movable):
var name: String
var vram: Int
fn fits(self, gb: Int) -> Bool:
return gb <= self.vram
fn main():
var g = Gpu("RTX 5090", 32)
print(g.name, "fits 16 GB:", g.fits(16))SIMD and parallelism
SIMD is a built-in type that maps to the CPU's vector registers. parallelize spreads work across cores.
from algorithm import parallelize
fn main():
var a = SIMD[DType.float32, 8](1.0)
var b = SIMD[DType.float32, 8](0.5)
print((a * b).reduce_add()) # 4.0
@parameter
fn work(i: Int):
print("chunk", i)
parallelize[work](4)AI with Mojo
Mojo's main job is AI performance: writing fast kernels for matrix multiplication and attention, custom operations for Modular's MAX engine, and GPU code without CUDA. You can also import Python modules, so NumPy and other libraries remain available.
The essential libraries
Use Python libraries from Mojo
Mojo can call into Python, so you can mix NumPy with fast Mojo code.
from python import Python
fn main() raises:
var np = Python.import_module("numpy")
var x = np.linspace(-1, 1, 100)
var y = 3 * x + 0.5
var w: Float64 = 0
var b: Float64 = 0
for _ in range(500):
var err = w * x + b - y
w -= 0.1 * Float64(py=(2 * (err * x).mean()))
b -= 0.1 * Float64(py=(2 * err.mean()))
print("w =", w, "b =", b)Build an AI agent with Mojo
Mojo has no mature HTTP library yet, so the practical way to build an agent is to call Python's requests through interop while keeping your fast tools in Mojo.
from python import Python
fn get_weather(city: String) -> String:
return "It is 24°C and sunny in " + city + "."
fn main() raises:
var requests = Python.import_module("requests")
var json = Python.import_module("json")
var url = "http://localhost:11434/v1/chat/completions"
var tools = json.loads('[{"type":"function","function":{"name":"get_weather","description":"Weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]')
var messages = Python.list()
messages.append(Python.dict(role="user", content="Should I take an umbrella in Lahore today?"))
for _ in range(5):
var body = Python.dict(model="llama3.1", messages=messages, tools=tools)
var msg = requests.post(url, json=body).json()["choices"][0]["message"]
messages.append(msg)
var calls = msg.get("tool_calls")
if not calls:
print(msg["content"])
break
for call in calls:
var args = json.loads(call["function"]["arguments"])
var result = get_weather(String(args["city"]))
messages.append(Python.dict(role="tool", tool_call_id=call["id"], content=result))Mojo's Python interop API is still evolving; check the current docs if a call has been renamed.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Mojo learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Mojo cheat sheet
| Task | Syntax |
|---|---|
| Variable | var x: Int = 5 |
| Strict function | fn f(x: Int) -> Int: |
| Python-style | def g(x): |
| Struct | struct P: var x: Int |
| SIMD | SIMD[DType.float32, 4](1.0) |
| Python module | Python.import_module("numpy") |
Common mistakes
- Mojo is not a full Python superset yet; many Python features are missing.
- Syntax and library names change between releases.
fnfunctions need types andraisesif they can throw.
Where to go next
- Mojo manual — official
- Mojo GPU puzzles — learn GPU kernels
- Modular blog — updates
On TensorCore.si: Python volume, CUDA volume.
Keyboard: [ previous language · ] next language · / search the library