Skip to main content
Version: Nightly

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, and Dict literals 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 for loop 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

  • var declarations in functions now support more flexible "patterns", allowing multiple values to be declared at once, for example var a, b = 4, 5 and var a, b : Int, Float64.

  • Mojo now supports the use of Python-style type patterns when declaring variables on first assignment without the var keyword. For example, x = 4; y: UInt8 = 5 declares both x and y, where x is inferred to the default type of Int whereas y gets the explicit type UInt8. Declaring variables without var gives you a function-scoped name, whereas var makes things scoped to the statement they are in (lexical scoping), such as the body of an if statement.

  • Mojo now supports ref patterns 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 it

    References 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__(), and copy() methods for structs that conform to Movable, Copyable, and ExplicitlyCopyable (respectively) but that do not implement the methods explicitly.

  • A new @fieldwise_init decorator 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 @value synthesizes. This decorator allows an optional @fieldwise_init("implicit") form for single-element structs, which marks the initializer as @implicit.

  • try and raise now 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 type T that is inferred by context, or otherwise defaulting to the standard library List type. The ListLiteral type has been removed from the standard library.

  • Dictionary and set literals now work and default to creating instances of the Dict and Set types 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 out or mut as an argument name any longer. Previously you could use fn x(out: Int), but this causes ambiguity with function types. Please use names like output instead.

  • def arguments are no longer implicitly mutable. If you would like to have a locally mutable argument, declare it owned explicitly.

  • 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.tcgen05 module 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() and prefix_sum() implementations in the gpu.block and gpu.warp modules. 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 Dict type is now part of the prelude, so there is no need to import it anymore.

    • The List, Span, Dict, Set, VariadicPack, and Deque iterators now return references to elements directly, instead of returning Pointer. 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 ref keyword 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, and SIMD types 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"]
    • Dict and Set support 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 BitSet data structure was added to the collections package. This is a fixed BitSet that simplifies working with a set of bits and performing bit operations.

    • VariadicList, VariadicListMem, and VariadicPack moved to the new variadics module.

    • The CollectionElement trait has been removed. You can replace any use of it with the Copyable and Movable traits, or the Copyable & Movable trait 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 and var d: PythonObject = {} will construct an empty dictionary.

  • Python.unsafe_get_python_exception() and Python.throw_python_exception_if_error_state() have been removed in favor of Python().cpython().unsafe_get_error() and Python().cpython().get_error().

  • Since virtually any operation on a PythonObject can raise, the PythonObject struct no longer implements the Indexer and Intable traits. Instead, it now conforms to IntableRaising, and users should convert explicitly to built-in types and handle exceptions as needed. In particular, the PythonObject.__int__() method now returns a Python int instead of a mojo Int, so users must explicitly convert to a mojo Int if they need one (and must handle the exception if the conversion fails, for example due to overflow).

  • PythonObject no longer implements the following traits:

    • Stringable. Instead, the PythonObject.__str__() method now returns a Python str object and can raise. The new Python.str() static method can also be used to convert an arbitrary PythonObject to a Python str object.

    • KeyElement. Since Python objects may not be hashable—and even if they are, they could theoretically raise in the __hash__() method—PythonObject cannot conform to Hashable. This has no effect on accessing Python dict objects with PythonObject keys, since __getitem__() and __setitem__() should behave correctly and raise as needed. Two overloads of the Python.dict() factory function have been added to allow constructing dictionaries from a list of key-value tuples and from keyword arguments.

    • EqualityComparable. The PythonObject.__eq__() and PythonObject.__ne__() methods need to return other PythonObject values to support rich comparisons. Code that previously compared PythonObject values should be wrapped in Bool() to perform the fallible conversion explicitly: if Bool(obj1 == obj2): ....

    • Floatable. An explicit, raising constructor is added to SIMD to allow constructing Float64 values from PythonObject values that implement __float__().

  • A new def_function() API was added to PythonModuleBuilder to allow declaring Python bindings for arbitrary functions that take and return PythonObjects. Similarly, a new def_method() API is added to PythonTypeBuilder to allow declaring Python bindings for methods that take and return PythonObjects.

  • The ConvertibleFromPython trait is now public. This trait is implemented by Mojo types that can be constructed by converting from a PythonObject. This is the reverse operation of the PythonConvertible trait.

  • Bool, Int, and String now implement ConvertibleFromPython.

  • 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 type object globally registered using PythonModuleBuilder.add_type().

  • PythonObject has 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 type T, and if so, returns an UnsafePointer[T]. Otherwise, an exception is raised.

    • PythonObject.unchecked_downcast_value_ptr[T]() unconditionally returns an UnsafePointer[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 UnsafePointer initializer for downcasting from a PythonObject.

    • The TypedPythonObject type has been removed. Use PythonObject instead.

    • The Python.is_type(x, y) static method has been removed. Use the expression x is y instead.

  • os.abort(messages) no longer supports a variadic number of Writable messages. 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 single StringLiteral message. We now no longer need to generate a bunch of bloated IR and instead, callers must create the String on their side before calling os.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 the e. For example 1.1385616158185648648648648648616186186e-3 won'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 new symmetrical parameter. 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 compile module now provides the get_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
  • Removed support for the command line option --emit-llvm in favor of --emit=llvm.

  • Added support for emitting assembly code (.s) using --emit=asm.

    • Example usage: mojo build --emit=asm YourModule.mojo
  • Added associated alias support for documentation generated via mojo doc.

  • Added struct and trait conformance list sorting support to mojo format.

❌ Removed

  • VariadicPack.each() and VariadicPack.each_idx() methods have been removed. Use the @parameter for language construct to achieve this now. The write_buffered() and write_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.sqrt products incorrect results for large inputs.
  • #4518 - Try Except Causes False Positive "Uninitialized Value".
  • #4677 - UIntN Comparison Yields Incorrect Result When Function Parameter Is Involved (UInt8UInt64).
  • #4684 - Failure inferring type of initializer list from field of struct.
  • #4668 - Incorrect result for unsigned gt and le comparisons.
  • #4694 - Compiler error handling x or y expressions with PythonObject.
  • #4719 - Dict.setdefault should not be marked with raises.

Special thanks

Special thanks to our community contributors:

@astrobdr, @bgreni, @gabrieldemarmiesse, @godardt, @hardikkgupta, @Hundo1018, @kirillbobyrev, @martinvuyk, @msaelices, @mzaks, @OwenJRJones, @shogo314, @sibarras, @simveit, @soraros, @sstadick