v25.4 (2025-06-18)
✨ Highlights
-
Mojo now supports AMD GPUs, expanding hardware compatibility beyond NVIDIA to include AMD's GPU ecosystem. This enables Mojo applications to leverage AMD's RDNA and CDNA architectures for high-performance computing workloads, providing developers with greater flexibility in choosing hardware platforms for AI and compute-intensive applications.
-
Primitives for working with NVIDIA Blackwell GPUs have been added, providing low-level access to the latest GPU architecture features. These primitives enable developers to take advantage of Blackwell's enhanced compute capabilities, improved memory bandwidth, and advanced AI acceleration features, including support for newer tensor operations and optimized memory management patterns.
-
The Python-Mojo bindings are available as a preview release! This is the ability to call into Mojo functions from existing Python codebases. The use case is to speed up hot spots/slow Python code by rewriting certain portions of your code in Mojo to achieve performance.
-
Mojo collection types received many enhancements.
-
List,Set, andDictliterals have been reimplemented to provide Python-equivalent features and syntax, including simple literals like[1, 2, 3]and{k1: v1, k2: v2}. -
List comprehensions like
[a*b for a in range(10) if isprime(a) for b in range(20)]as well as dictionary and set comprehensions are now supported. -
Iterating over a collection with a
forloop no longer requires using the[]deference operator.
See Language enhancements and Standard library changes for more details.
-
-
The entire MAX Kernel library is now fully open sourced! For more information, see the MAX AI kernels library reference and the MAX AI kernels source.
-
Mojo is now available on Godbolt.org, which is also known as the "Compiler Explorer".
Language enhancements
-
vardeclarations in functions now support more flexible "patterns", allowing multiple values to be declared at once, for examplevar a, b = 4, 5andvar a, b : Int, Float64. -
Mojo now supports the use of Python-style type patterns when declaring variables on first assignment without the
varkeyword. For example,x = 4; y: UInt8 = 5declares bothxandy, wherexis inferred to the default type ofIntwhereasygets the explicit typeUInt8. Declaring variables withoutvargives you a function-scoped name, whereasvarmakes things scoped to the statement they are in (lexical scoping), such as the body of anifstatement. -
Mojo now supports
refpatterns that bind a stored LValue into a named declaration, extending the argument convention into local function scope.This can be useful when you want to do something with a reference, but don't want the conceptual overhead of a
Pointer. These are equivalent:fn use_pointer(your_list: List[Int]):
var p = Pointer(to=your_list[i]) # Form a safe pointer
...
use(p[]) # dereference it
fn use_ref(your_list: List[Int]):
ref r = your_list[i] # Bind element reference to 'r'
...
use(r) # use itReferences are bound in their initializer and cannot be mutated afterward: uses and mutations of the reference are interpreted as uses and mutations of the value referenced by the value.
-
The Mojo compiler will now synthesize
__moveinit__(),__copyinit__(), andcopy()methods for structs that conform toMovable,Copyable, andExplicitlyCopyable(respectively) but that do not implement the methods explicitly. -
A new
@fieldwise_initdecorator can be attached to structs to synthesize a field-wise initializer—an__init__()method that takes the same arguments as the fields in the struct. This gives access to this helpful capability without having to opt into the rest of the methods that@valuesynthesizes. This decorator allows an optional@fieldwise_init("implicit")form for single-element structs, which marks the initializer as@implicit. -
tryandraisenow work at compile time. -
"Initializer lists" are now supported for creating struct instances with an inferred type based on context, for example:
fn foo(x: SomeComplicatedType): ...
# Example with normal initializer.
foo(SomeComplicatedType(1, kwarg=42))
# Example with initializer list.
foo({1, kwarg=42}) -
List literals have been redesigned to work better. They produce homogenous sequences by invoking the
T(<elements>, __list_literal__: ())constructor of a typeTthat is inferred by context, or otherwise defaulting to the standard libraryListtype. TheListLiteraltype has been removed from the standard library. -
Dictionary and set literals now work and default to creating instances of the
DictandSettypes in the collections library.
Language changes
-
Implicit trait conformance is deprecated. Each instance of implicit conformance results in a warning, but compilation still goes through. Soon it will be upgraded into an error. Any code currently relying on implicit conformance should either declare conformances explicitly or, if appropriate, replace empty, non-load-bearing traits with trait compositions.
-
Mojo doesn't allow the use of
outormutas an argument name any longer. Previously you could usefn x(out: Int), but this causes ambiguity with function types. Please use names likeoutputinstead. -
defarguments are no longer implicitly mutable. If you would like to have a locally mutable argument, declare itownedexplicitly. -
Global (file-scope) variables are deprecated. Global variables in Mojo are only partially implemented and are known to cause cryptic errors. Now the Mojo compiler issues a warning on global variable usage.
Standard library changes
-
GPU programming enhancements and changes:
-
Mojo now supports AMD GPUs, expanding hardware compatibility beyond NVIDIA to include AMD's GPU ecosystem. This enables Mojo applications to leverage AMD's RDNA and CDNA architectures for high-performance computing workloads, providing developers with greater flexibility in choosing hardware platforms for AI and compute-intensive applications.
-
Primitives for working with NVIDIA Blackwell GPUs have been added, providing low-level access to the latest GPU architecture features. These primitives enable developers to take advantage of Blackwell's enhanced compute capabilities, improved memory bandwidth, and advanced AI acceleration features, including support for newer tensor operations and optimized memory management patterns. See the
gpu.tcgen05module API reference documentation for more information. -
Added support for a wider range of consumer-grade hardware, including:
- NVIDIA RTX 2060 GPUs
- NVIDIA RTX 4090 GPUs
-
Fixed the
sum()andprefix_sum()implementations in thegpu.blockandgpu.warpmodules. Previously, the implementations have been incorrect and would either return wrong results or hang the kernel (due to the deadlock). PR 4508 and PR 4553 by Kirill Bobyrev mitigate the found issues and add tests to ensure correctness going forward.
-
-
Collection type enhancements and changes:
-
The
Dicttype is now part of the prelude, so there is no need to import it anymore. -
The
List,Span,Dict,Set,VariadicPack, andDequeiterators now return references to elements directly, instead of returningPointer. This means that you should no longer use the[]deference operator with the loop index variable:var states: List[String] = ["California", "Hawaii", "Oregon"]
# Old:
for state in states:
print(state[])
# New:
for state in states:
# state is an immutable reference
print(state)By default the reference is immutable. You can use the
refkeyword to bind the index variable as a mutable reference:for ref state in states:
# state is a mutable reference
state += "!" # Update the existing list element -
List,InlineArray,Deque,LinkedList, andSIMDtypes all support construction via list literal syntax:var list: List[Int] = [1, 2, 3]
var vec: SIMD[DType.uint8, 8] = [1, 2, 3, 4, 5, 6, 7, 8]
var deque: Deque[Float64] = [1, 2.5]
var llist: LinkedList[Int] = [1, 2, 3]
var arr: InlineArray[String, 3] = ["hi", "hello", "hey"] -
DictandSetsupport construction via dict literal and set literal syntax, respectively:var dict1 = {String("foo"): 1, String("bar"): 2} # Dict[String, Int]
var dict2 = {1: 4, 2: 7, 3: 18} # Dict[Int, Int]
var set = {1, 2, 3} # Set[Int] -
Python-style list, dictionary, and set comprehensions are now supported. For example:
# Basic list comprehension using a List[String]
var upper_strs = [str.upper() for str in strs] # List[String]
# Nested list comprehension with conditional expression
var nums = [a * b for a in range(1, 5) if a % 2 == 0 for b in [-1, 1]] # List[Int]
# Dictionary comprehension
var squares_dict = {num: num * num for num in range(10)} # Dict[Int, Int]
# Set comprehension
var unique_remainders = {num % 4 for num in range(10)} # Set[Int] -
The
BitSetdata structure was added to thecollectionspackage. This is a fixedBitSetthat simplifies working with a set of bits and performing bit operations. -
VariadicList,VariadicListMem, andVariadicPackmoved to the newvariadicsmodule. -
The
CollectionElementtrait has been removed. You can replace any use of it with theCopyableandMovabletraits, or theCopyable & Movabletrait composition.
-
Python-Mojo interoperability enhancements and changes:
-
Python objects are now constructible with list, set, and dict literal syntax, for example:
var list: PythonObject = [1, "foo", 2.0]will produce a Python list containing other Python objects andvar d: PythonObject = {}will construct an empty dictionary. -
Python.unsafe_get_python_exception()andPython.throw_python_exception_if_error_state()have been removed in favor ofPython().cpython().unsafe_get_error()andPython().cpython().get_error(). -
Since virtually any operation on a
PythonObjectcan raise, thePythonObjectstruct no longer implements theIndexerandIntabletraits. Instead, it now conforms toIntableRaising, and users should convert explicitly to built-in types and handle exceptions as needed. In particular, thePythonObject.__int__()method now returns a Pythonintinstead of a mojoInt, so users must explicitly convert to a mojoIntif they need one (and must handle the exception if the conversion fails, for example due to overflow). -
PythonObjectno longer implements the following traits:-
Stringable. Instead, thePythonObject.__str__()method now returns a Pythonstrobject and can raise. The newPython.str()static method can also be used to convert an arbitraryPythonObjectto a Pythonstrobject. -
KeyElement. Since Python objects may not be hashable—and even if they are, they could theoretically raise in the__hash__()method—PythonObjectcannot conform toHashable. This has no effect on accessing Pythondictobjects withPythonObjectkeys, since__getitem__()and__setitem__()should behave correctly and raise as needed. Two overloads of thePython.dict()factory function have been added to allow constructing dictionaries from a list of key-value tuples and from keyword arguments. -
EqualityComparable. ThePythonObject.__eq__()andPythonObject.__ne__()methods need to return otherPythonObjectvalues to support rich comparisons. Code that previously comparedPythonObjectvalues should be wrapped inBool()to perform the fallible conversion explicitly:if Bool(obj1 == obj2): .... -
Floatable. An explicit, raising constructor is added toSIMDto allow constructingFloat64values fromPythonObjectvalues that implement__float__().
-
-
A new
def_function()API was added toPythonModuleBuilderto allow declaring Python bindings for arbitrary functions that take and returnPythonObjects. Similarly, a newdef_method()API is added toPythonTypeBuilderto allow declaring Python bindings for methods that take and returnPythonObjects. -
The
ConvertibleFromPythontrait is now public. This trait is implemented by Mojo types that can be constructed by converting from aPythonObject. This is the reverse operation of thePythonConvertibletrait. -
PythonObject(alloc=<value>)is a new constructor that can be used to directly store Mojo values in Python objects.This initializer will fail if the type of the provided Mojo value has not previously had a corresponding Python
typeobject globally registered usingPythonModuleBuilder.add_type(). -
PythonObjecthas new methods for downcasting to a pointer to a contained Mojo value, for use in Python/Mojo interop.struct Person:
var name: String
fn greet(obj: PythonObject) raises:
var person = obj.downcast_value_ptr[Person]()
print("Hello ", person[].name, "from Mojo🔥!")-
PythonObject.downcast_value_ptr[T]()checks if the object is a wrapped instance of the Mojo typeT, and if so, returns anUnsafePointer[T]. Otherwise, an exception is raised. -
PythonObject.unchecked_downcast_value_ptr[T]()unconditionally returns anUnsafePointer[T]without any runtime type checking. This is useful when using Python/Mojo interop to optimize an inner loop and minimizing overhead is desirable.Also added an equivalent
UnsafePointerinitializer for downcasting from aPythonObject. -
The
TypedPythonObjecttype has been removed. UsePythonObjectinstead. -
The
Python.is_type(x, y)static method has been removed. Use the expressionx is yinstead.
-
-
os.abort(messages)no longer supports a variadic number ofWritablemessages. While this API was high-level and convenient, it generated a lot of IR for simple and common cases, such as when we have a singleStringLiteralmessage. We now no longer need to generate a bunch of bloated IR and instead, callers must create theStringon their side before callingos.abort(message). -
The
atof()function has been entirely rewritten as it produced incorrect results for very low and very high exponents. It now works correctly for strings with fewer than 19 digits left of thee. For example1.1385616158185648648648648648616186186e-3won't work, and will raise an error. Anything that does not produce an error is now guaranteed to be correct. While the current implementation is not the fastest, it's based on the paper Number Parsing at a Gigabyte per Second by Daniel Lemire. So with a bit of effort to pinpoint the slow parts, we can easily have state of the art performance in the future. -
The
math.isclose()function now supports both symmetric (Python-style) and asymmetric (NumPy-style) comparison modes via a newsymmetricalparameter. The parameter defaults to the newly added symmetric support. The function now only supports floating-point types, removing previous pseudo-support for integer and boolean types. Support added in PR 4608 by @soraros. -
The
compilemodule now provides theget_type_name()function to get the fully qualified name of a type. For example,compile.get_type_name[Int]()returns"std.builtin.int.Int".
Tooling changes
-
Added support for emitting LLVM Intermediate Representation (.ll) using
--emit=llvm.- Example usage:
mojo build --emit=llvm YourModule.mojo
- Example usage:
-
Removed support for the command line option
--emit-llvmin favor of--emit=llvm. -
Added support for emitting assembly code (.s) using
--emit=asm.- Example usage:
mojo build --emit=asm YourModule.mojo
- Example usage:
-
Added associated alias support for documentation generated via
mojo doc. -
Added struct and trait conformance list sorting support to
mojo format.
❌ Removed
-
VariadicPack.each()andVariadicPack.each_idx()methods have been removed. Use the@parameter forlanguage construct to achieve this now. Thewrite_buffered()andwrite_args()functions have also been removed, to improve compile speed and reduce register pressure on GPU, you should now unroll the variadic pack at each call site:Unbuffered:
fn write[*Ts: Writable](mut self, *args: *Ts):
var string = String()
@parameter
for i in range(args.__len__()):
args[i].write_to(string)Buffered:
from utils.write import _WriteBufferStack
fn write[*Ts: Writable](mut self, *args: *Ts):
var string = String()
var buffer = _WriteBufferStack(string)
@parameter
for i in range(args.__len__()):
args[i].write_to(buffer)
buffer.flush()
🛠️ Fixed
- #1649 - Trailing comma is not supported in assignments.
- #3415 - Type annotation fails on implicit variable declarations.
- #4352 -
math.sqrtproducts incorrect results for large inputs. - #4518 - Try Except Causes False Positive "Uninitialized Value".
- #4677 -
UIntNComparison Yields Incorrect Result When Function Parameter Is Involved (UInt8–UInt64). - #4684 - Failure inferring type of initializer list from field of struct.
- #4668 - Incorrect result for
unsigned
gtandlecomparisons. - #4694 - Compiler error
handling
x or yexpressions with PythonObject. - #4719 -
Dict.setdefaultshould not be marked withraises.
Special thanks
Special thanks to our community contributors:
@astrobdr, @bgreni, @gabrieldemarmiesse, @godardt, @hardikkgupta, @Hundo1018, @kirillbobyrev, @martinvuyk, @msaelices, @mzaks, @OwenJRJones, @shogo314, @sibarras, @simveit, @soraros, @sstadick