v0.25.6 (2025-09-22)
✨ Highlights
-
You can now
pip install mojo!Although we still love the environment reliability of Pixi, installing Mojo with
piporuvfurther enhances our interoperability with the Python ecosystem, making it easier to extend your Python code with Mojo. For more information, see the Mojo install guide. -
We've released a new version of the Mojo extension for Visual Studio Code that now works with both the stable and nightly Mojo releases. You can install the Mojo extension from either the Visual Studio Code Marketplace or the Open VSX Registry.
The new extension replaces the old stable version, so if you have the stable version installed, you can simply update it to receive the new version. If you have the nightly version of the extension installed, you should uninstall it and install the regular (non-nightly) version. See Add the VS Code extension for more information.
-
New Mojo vision doc explains our motivations and design decisions for the Mojo language.
-
New Mojo roadmap provides a high-level roadmap for the language across multiple phases.
-
Mojo now has support for default trait methods, allowing traits to provide reusable behavior without requiring every conforming struct to re-implement it. Default methods are automatically inherited by conforming structs unless explicitly overridden. See Default method implementations in the Mojo Manual for more information.
-
Added support for many consumer GPUs, including initial support for Apple silicon GPUs. See GPU support for details.
-
The way copying is modeled in Mojo has been overhauled. The
Copyabletrait has been updated to represent a type that can be explicitly copied (using acopy()method), and a newImplicitlyCopyable"marker" trait can be used to opt-in to making a type implicitly copyable as well. This swaps the default behavior from being implicitly copyable to being only explicitly copyable. Several standard library traits, types, and functions now require now require explicitCopyableinstead ofImplicitlyCopyable. See Standard library changes for more information. -
Uncaught exceptions or segmentation faults in Mojo programs can now generate stack traces. This is currently only for CPU-based code. To generate a fully symbolicated stack trace, set the
MOJO_ENABLE_STACK_TRACE_ON_ERRORenvironment variable, usemojo buildwith debug info enabled, e.g.-debug-level=line-tables, and then run the resulting binary. -
Major standard library improvements include:
-
Making the
SIMDtype conform toComparableandEqualityComparable, which means that you can useSIMDvalues asDictkeys, among other things. For details, see SIMD and related types. -
A new
Some[Trait]utility to make it easier to declare an argument that conforms to a trait. For details, see Other standard library changes. -
Several enhancements to how iterators work in Mojo, including a new
Iterabletrait. For more information, see Collections and iterators changes.
-
Language enhancements
-
Mojo now allows the use of keywords in function names (after
defandfn) and in attribute references after a.. This notably allows the use of thematch()method in regex libraries even though Mojo takes this as a hard keyword. Uses in other locations can still use backticks:struct MatchExample:
fn match(self): # This is ok now.
pass
fn test_match(a: MatchExample):
a.match() # This is ok now.
a.`match`() # This is still valid. -
When generating error messages for complex types involving parameter calls, the Mojo compiler now prints functions parameter values correctly, eliminating a large class of
T != Terrors that happen with GPU layouts.
Language changes
-
Methods on structs may now declare their
selfargument with adeinitargument convention. This argument convention is used for methods like__del__()and__moveinit__()to indicate that they tear down the corresponding value without needing its destructor to be run again. Beyond these two methods, this convention can be used to declare "named" destructors, which are methods that consume and destroy the value without themselves running the values destructor. For example, the standardVariadicPacktype has these methods:struct VariadicPack[...]:
# implicit destructor
fn __del__(deinit self): ...
# move constructor
fn __moveinit__(out self, deinit existing: Self): ...
# custom explicit destructor that destroys "self" by transferring all of
# the stored elements.
fn consume_elements[
elt_handler: fn (idx: Int, var elt: element_type) capturing
](deinit self): ...This argument convention is a fairly narrow power-user feature that is important to clarify the destruction model and make linear types fit into the model better. (A linear type is just a type that has no
__del__()method, but provides a destructor that the user must call explicitly. Linear types are a proposed feature that hasn't been fully implemented yet.)-
The
__del__()and__moveinit__()methods should now take theirselfandexistingarguments asdeinitinstead of eitherownedorvar. -
The
__disable_delkeyword and statement has been removed, usedeinitmethods instead.
-
-
The Mojo compiler now warns about use of the deprecated
ownedkeyword, please move tovarordeinitas the warning indicates. -
The previously deprecated
@valuedecorator has been removed. -
Accesses to associated aliases and methods within a trait now require qualified references (prepended with
Self.), making it consistent with how accesses to member aliases and methods in a struct requireself.. -
The Mojo compiler now raises error on implicit materialization of a non-
ImplicitlyCopyableobject, please either mark the type to beImplicitlyCopyableor usingmaterialize[value: T]()to explicitly materialize the parameter into a dynamic value.This usually happens when you generate a compile-time value using the
aliaskeyword, then assign it to a runtime variable:alias lst = [1, 2, 3, 4] # Create a compile-time list value
var dyn_list = lst # Implicitly materializes the compile-time value to a
# dynamically-allocated runtime valueThe alias is a compile-time temporary value; to assign it to a runtime variable, Mojo must allocate memory and copy the value. Since this can result in unexpected memory allocations when materializing a memory value like a list, Mojo only allows implicit materializations of memory values if the type is
ImplicitlyCopyable, which is a signal that the type should be inexpensive to copy.You can use the
materialize()function to explicitly materialize a value:var dyn_list = materialize[lst]()
Standard library changes
Copyability changes
-
The way copying is modeled in Mojo has been overhauled.
Previously, Mojo had two traits for modeling copyability:
Copyabledenoted a type that could be copied implicitlyExplicitlyCopyabledenoted a type that could only be copied with an explicit call to a.copy()method.
The vast majority of types defaulted to implementing
Copyable(and therefore were implicitly copyable), andExplicitlyCopyablewas partially phased in but had significant usage limitations.Now, the new
Copyabletrait instead represents a type that can be explicitly copied (using.copy()), and a newImplicitlyCopyable"marker" trait can be used to opt-in to making a type implicitly copyable as well. This swaps the default behavior from being implicitly copyable to being only explicitly copyable.The new
ImplicitlyCopyabletrait inherits fromCopyable, and requires no additional methods.ImplicitlyCopyableis known specially to the compiler. (ImplicitlyCopyabletypes may also be copied explicitly using.copy().)This makes it possible for non-implicitly-copyable types to be used with all standard library functionality, resolving a long-standing issue with Mojo effectively forcing implicit copyability upon all types. This will enable Mojo programs to be more efficient and readable, with fewer performance and correctness issues caused by accidental implicit copies.
With this change, types that conform to
Copyableare no longer implicitly copyable:@fieldwise_init
struct Person(Copyable):
var name: String
fn main():
var p = Person("Connor")
var p2 = p # ERROR: not implicitly copyable
var p3 = p.copy() # OK: may be copied explicitlyTo enable a type to be implicitly copyable, declare a conformance to the
ImplicitlyCopyablemarker trait:@fieldwise_init
struct Point(ImplicitlyCopyable):
var x: Float32
var y: Float32
fn main():
var p = Point(5, 10)
var p2 = p # OK: may be implicitly copied
var p3 = p.copy() # OK: may be explicitly copiedAn additional nuance is that
ImplicitlyCopyablemay only be synthesized for types whose fields are all themselvesImplicitlyCopyable(and not merelyCopyable). If you need to make a type with any non-ImplicitlyCopyablefields support implicit copying, you can declare the conformance toImplicitlyCopyable, but write the__copyinit__()definition manually:struct Container(ImplicitlyCopyable):
var x: SomeCopyableType
var y: SomeImplicitlyCopyableType
fn __copyinit__(out self, existing: Self):
self.x = existing.x.copy() # Copy field explicitly
self.y = existing.yFor more information on copyability, see the section on copy constructors in the Mojo manual.
-
The following standard library types and functions now require only explicit
Copyablefor their element and argument types, enabling their use with types that are not implicitly copyable:List,Span,InlineArrayOptional,Variant,Tuple,Dict,Set,Counter,LinkedList,Deque, andreversed().Additionally, the following traits now require explicit
Copyableinstead ofImplicitlyCopyable:KeyElement,IntervalElement,ConvertibleFromPython -
The following Mojo standard library types are no longer implicitly copyable:
List,Dict,DictEntry,OwnedKwargsDict,Set,LinkedList,NodeCounter,CountTuple,BitSet,UnsafeMaybeUninitialized,DLHandle,BenchConfig,BenchmarkInfo,Report,PythonTypeBuilder.To create a copy of one of these types, call the
.copy()method explicitly:var l = List[Int](1, 2, 3)
# ERROR: Implicit copying of `List` is no longer supported:
# var l2 = l
# Instead, perform an explicit copy:
var l2 = l.copy()Alternatively, to transfer ownership, use the
^transfer sigil:var l = List[Int](1, 2, 3)
var l2 = l^
# `l` is no longer accessible. -
Because
ListandDictare so widely used, this release stages this in by making implicit copies of these types a warning instead of an error. This will become a hard error in the next release of Mojo. -
User types that define a custom
.copy()method must be updated to move that logic to__copyinit__(). The.copy()method is now provided by a default trait implementation onCopyablethat should not be overridden:trait Copyable:
fn __copyinit__(out self, existing: Self, /):
...
fn copy(self) -> Self:
return Self.__copyinit__(self)
SIMD and related types
-
The comparison operators (e.g.
__eq__()and__le__()) of theSIMDtype now return a singleBoolinstead of a booleanSIMDmask. Moreover,SIMDnow has explicit element-wise comparisons that return boolean masks (for example,eq()andle()).- This allows
SIMDto conform to theEqualityComparabletrait, enabling the use ofSIMDvectors in sets, as keys to dictionaries, generic search algorithms, etc. Moreover,Scalarnow conforms to theComparabletrait, i.e.SIMDconforms toComparablewhen the size is 1. - As a consequence,
SIMD.__bool__()no longer needs to be restricted to scalars, and instead performs ananyreduction on the elements of vectors.
- This allows
-
Non-scalar
SIMDconstructors no longer allow implicit splatting ofBoolvalues. This could lead to subtle bugs that cannot be caught at compile time, for example:fn foo[w: Int](v: SIMD[_, w]) -> SIMD[DType.bool, w]:
return v == 42 # this silently reduced to a single bool, and then splatSimilarly to
InlineArray, an explicit constructor with thefillkeyword-only argument can be used to express the same logic more safely:fn foo[w: Int](v: SIMD[_, w]) -> SIMD[DType.bool, w]:
return SIMD[DType.bool, w](fill=(v == 42)) # highlights the splat logic
fn bar(Scalar[_]) -> Scalar[DType.bool]:
# still works, since implicit splatting to a scalar is never ambiguous
return v == 42 -
Several types that wrap MLIR types have been changed to further encapsulate their behavior, hiding this low-level behavior from non-advanced users.
-
Types that can be constructed from raw MLIR values now require the use of an
mlir_valuekeyword-only argument initializer. Affected types includeSIMDandUInt. -
Types with raw MLIR type fields have had their
valuefields renamed to_mlir_value. Affected types include:BoolandDType.
-
-
The
SIMD.from_bits()factory method is now a constructor, useSIMD(from_bits=...)instead. -
DType.indexis deprecated in favor of the newDType.int. Moreover, a newDType.uintis added, modeling unsigned integers with widths that match the machine word length. -
The
index()free function now returns anInt, instead of a raw MLIR__mlir_type.indexvalue.
Path and file system changes
-
Added the
parts()method to thePathtype, for example instead of writing:var path = Path("path/to/file")
var parts = path.path.split(DIR_SEPARATOR)you can now write:
var path = Path("path/to/file")
var parts = path.parts() -
Added the
name()method to thePathtype, which returns the name of the file or directory. -
Added
os.path.realpath()to resolve symbolic links to an absolute path and remove relative path components (.,.., etc.). Behaves the same as the Python equivalent function.
Collections and iterators changes
-
Added an
itermodule which includes the newIterabletrait (and the existingIteratortrait). The module also provides theenumerate(),iter(),map(),next(), andzip()functions. The new genericzip()function replaces theIntTuple-specificzip()function provided in previous releases.Iterable'soriginparameter is now namediterable_originand itsmutparam is now namediterator_mutto avoid naming collisions.
-
Iteratornow has a defaultedbounds()trait method. This returns the lower and upper bounds of the remaining length of the iterator. This can be used for preallocation when building or extending collections from iterators. -
Added
take_items()draining iterator toDict. -
Spanis nowRepresentableif its elements implement theRepresentabletrait. -
Add
repr()support forList,Deque,Dict,LinkedList,Optional, andSet. -
InlineArraynow automatically detects whether its element types are trivially destructible to not invoke the destructors in its__del__()function. This improves performance for trivially destructible types (such asIntand friends). -
Similar to above,
Listnow automatically does optimizations based on whether the element types are trivial (copyable, destructible, etc). There is no longer ahint_trivial_typeparameter as this is done automatically now. -
String.splitlines()now returns aList[StringSlice]instead of aList[String]. This avoids unnecessary intermediate allocations. -
StringSlice.from_utf8()factory method is now a constructor, useStringSlice(from_utf8=...)instead. -
Spannow implements a generic.count()method which can be passed a function that returns a booleanSIMDvector. The function counts how many times it returnsTrueevaluating it in a vectorized manner. This works for anySpan[Scalar[D]]e.g.Span[Byte]. -
OptionalandOptionalRegcan now be composed withBoolin expressions, both at comptime and runtime:alias value = Optional[Int](42)
@parameter
if CompilationTarget.is_macos() and value:
print("is macos and value is:", value.value()) -
sort(),LinkedList.pop(),LinkedList.maybe_pop()andDict.popitem()no longer copy elements, improving performance. -
The
IndexListandDimListtypes may no longer be implicitly constructed from tuple values. Most existing call sites already used explicit initializer calls (IndexList(...)), so implicit conversions have been removed to ensure uniformity and consistency.
Pointer changes
-
Removed the
alignmentparameter andstatic_alignment_cast()method fromUnsafePointer. Thisalignmentparameter that was only used by thealloc()static method. -
Added an
alignmentkeyword argument toUnsafePointer.alloc(). Use this in place of thealignmentparameter on the struct. -
Removed the
alignmentparameter fromSpan, similar toUnsafePointerabove. -
The
UnsafePointer.init_pointee_explicit_copy()method has been removed. Please useUnsafePointer.init_pointee_copy()instead. -
UnsafePointer.move_pointee_into()has been deprecated. Please useUnsafePointer.init_pointee_move_from().src.move_pointee_into(dst)used a reversed argument order from intuitiveLHS = RHSsemantics for assignment, effectivelyRHS -> LHS. The new function fixes this readability issue (dst.init_pointee_move_from(src)), and additionally follows theinit_pointee_*()naming convention of the other existing methods for initializer a pointer memory location.
Atomic operations
-
Added
os.atomic.fence()for creating atomic memory fences.from os.atomic import Atomic, Consistency, fence
fn decrease_ref_count(ref_count: Atomic[DType.uint64]):
if atomic.fetch_sub[ordering = Consistency.MONOTONIC](1) == 1:
fence[Consistency.ACQUIRE]()
# ... -
Add a memory ordering parameter to
Atomic.load().
System changes
-
Added
sys.info.platform_map()for specifying types that can have different values depending on the platform:from sys.info import platform_map
alias EDEADLK = platform_map["EDEADLK", linux = 35, macos = 11]() -
Renamed a number of functions following functions in
sys.infofromflatcasetosnake_casenames:Old name New name alignof()align_of()bitwidthof()bit_width_of()simdbitwidth()simd_bit_width()simdbytewidth()simd_byte_width()simdwidthof()simd_width_of()sizeof()size_of()The old names are deprecated, and will be removed in the next release.
GPU Support
-
Added initial support for programming Apple Silicon GPUs in Mojo. However, MAX graphs are not yet enabled on Apple Silicon GPUs, and many hardware features remain to be enabled.
-
Added support for AMD RX 6900 XT consumer-grade GPU.
-
Added support for AMD RDNA3.5 consumer-grade GPUs in the
gfx1150,gfx1151, andgfx1152architectures. Representative configurations have been added for AMD Radeon 860M, 880M, and 8060S GPUs. -
Added support for NVIDIA GTX 1080 Ti consumer-grade GPUs.
-
Added support for NVIDIA Tesla P100 datacenter GPUs.
-
Updated
layout_tensor()copy related functions to support 2D and 3D threadblock dimensions.
Other standard library changes
-
A new
Someutility is introduced to reduce the syntactic load of declaring function arguments of a type that implements a given trait or trait composition. For example, instead of writingfn foo[T: Intable, //](x: T) -> Int:
return x.__int__()one can now write:
fn foo(x: Some[Intable]) -> Int:
return x.__int__() -
The
compile.reflection.get_type_name()utility now has limited capability to print parametric types, e.g.SIMD[DType.float32, 4]instead of justSIMD. If the parameter is not printable, an<unprintable>placeholder is printed instead. A newqualified_builtinsflag also allows users to control the verbosity for the most common (but not all) builtin types.
Kernels changes
-
A fast matmul for SM100 is available in Mojo. Please check it out in
matmul_sm100.mojo. -
Moved the
commmodule from the standard library (gpu.comm) to the MAX AI kernels library. Any imports that usedgpu.commshould be updated tocomm, instead.
Tooling changes
-
mojo testnow ignores folders with a leading.in the name. This will exclude hidden folders on Unix systems. -
mojo doc --validate-doc-stringsnow emits a warning when anfnfunction is declared to raise an error (raises) and it has noRaisesdocstring. However, because Mojo automatically treats alldeffunctions as raising functions, we do not enforceRaisesdocs fordeffunctions (to avoid noisy false positives). -
Nightly
mojoPython wheels are now available. To install everything needed for Mojo development in a Python virtual environment, you can use:pip install --pre mojo \
--index-url https://dl.modular.com/public/nightly/python/simple/For more information, see the Mojo install guide.
-
In preparation for a future Mojo 1.0, the
mojoandmojo-compilerpackages have a0.prefixed to the version.
❌ Removed
- The Mojo MLIR C bindings has been removed. This was a private package that was used for early experimentation.
🛠️ Fixed
- #4695 -
Dict.__getitem__()always returns immutable references. - #4705 - Wrong mutability
inferred for
__getitem__()if[]operator is used and__setitem__()is present. - #5190 - Mojo compiler crashes for a struct with two constructors taking different keyword-only arguments.
- #5139 - Crash on malformed initializer.
- #5183 -
Log1p()not working on GPUs. - #5105 - Outdated
CLAUDE.mddocs. - #5239 - Contextual type not detected inside an inline if-else.
- #5305 - Parser Segfaults on
LayoutTensor[layout]with nolayoutin scope. - #5260 - Undefined reference to `clock_gettime_nsec_np' when building with -O0.
- #5307 - Bad error message when getting GPU info for unsupported GPU.
- Error messages involving types using implicit parameters from auto-parameterized types now include context information to solve a class of incorrect "T != T" error messages common in kernel code.
- Parameter inference failures now refer to parameters by their user-provided name, rather than complaining about a mysterious "parameter #4".
Special thanks
Special thanks to our community contributors: @AceMouse, @Alex-Mann, @christoph-schlumpf, @cudawarped, @cyrillzadra, @dl-alexandre, @farnoy, @gabrieldemarmiesse, @gryznar, @josiahls, @kyoto7250 @martinvuyk, @mmicu, @msaelices, @mzaks, @rd4com, @Rtosshy, @SasankYadati, @simonyjung, @soraros, and @ThomasMader.