This month in Julia World - 2026-10

A monthly newsletter, mostly on Julia internals, digestible for casual observers. A biased, incomplete, editorialized list of what a clique of us found interesting this month, with contributions from the community.

If you want to receive the newsletter as an email, subscribe to the Community–Newsletter category on Discourse.

Please feel free to post below with your own interesting finds, or in-depth explanations, or questions about these developments.

If you would like to help with the draft for next month, please drop your short, well formatted, linked notes in this shared document. Some of it might survive by the time of posting

I am pulling back from writing these monthly newsletters for the foreseeable future, because my personal life suddenly got very busy: Like Stefan who edited the newsletter before me, I also had a baby! I hope someone, or several people, will step up to continue the newsletter.

General

Current status (as of 2026-11-01): The latest Julia release is 1.13.3, and the LTS release is 1.10.12. The master branch is at 1.15.0-DEV.318, and Julia 1.14-alpha2 is available for testing.

Julia development is accelerating. The number of opened PRs to JuliaLang/julia went from 297 in July, 282 in August (where JuliaCon took out about a week’s time), 435 in September, and 752 in October. A year ago, the repo merged less than 50 commits a week, now it merges around 125. Kristoffer Carlsson alone has opened more than 100 PRs to JuliaLang/julia in October.

This is probably partially because AI agents speed up development in general, but may also be because AI agents facilitate a workflow where a developer does a deep dive into a subject and makes a spree of smaller PRs related to that subject. For this reason, some of the many changes this month is not easily summarized by single PRs that I can link to.

Core repos

  • Ian Butterworth and Kristoffer Carlsson have been working hard improving latency: They have been improving significantly on the Julia performance tracker to instrument where to look. Then, they have contributed dozes of latency-reducing PRs to Julia this month. All their PRs have not yet landed, but it is already clear that Julia 1.14 will have load times, precompile times and hot-cache script run times 30-50% lower than Julia 1.10, making 1.14 the fastest Julia release by far. This has been achieved incrementally, via a large number of PRs, many improving compile times by just a few percent. There are too many PRs to list them individually, but one PR especially stands out: #63656, which cut load times by about 30%. In my opinion, Ian’s and Kristoffer’s efforts may result in the greatest user experience improvement in Julia since its 1.0 release in 2018.

  • Jacob Quinn and Kristoffer Carlsson has brought some of the parsing infrastructure from Parsers.jl to Base Julia. This includes speeding up decimal integer parsing, hex parsing, re-implementing float parsing in Julia, and speeding up UUID parsing and Bool parsing. The new code lives in a Base.Parsers, and has an API different from Base.parse, which is still not public. The main benefit of the new API is that its failure return value tells the user what specific parsing failure occurred. This allows users to e.g. pick a wider type if integer parsing failed due to overflow.

  • At JuliaCon 2025 more than a year ago, Stefan Karpinski revealed his new SAT-based package resolver. This now powers Pkg.jl. It’s faster, provides pareto-optimal solutions, and gives better resolution conflict messages. It can also be upgraded later to allow resolving for other orderings, like choosing the oldest packages or optimizing for minimal download.

  • Julia’s installed size has grown significantly over time, from about 600 MB in Julia 1.10, to over 1,000 MB on Julia 1.13, and pushing 1,250 MB on nightly a month ago. To combat this, Kristoffer Carlsson has built a Rust CLI tool to inspect package- and system images, allowing him to see what bloats the images. He has also started tracking these sizes on perf.julialang.org. Using the tool, he has made a large number of PRs to reduce the installation size, which is now down to 668 MB on nightly. There are too many PRs to mention them all, but particularly notable changes include no longer distributing boundschecked stdlib images, and removing full debug info from the runtime.

  • LLVM has been updated to v23, and support for any previous version has been dropped. LLVM 23 is slightly (perhaps 5%) faster than previous versions, and this LLVM update is among the many changes that has led to the great latency reduction in Julia this month.

  • Oscar Smith is attempting to replace the trignometry functions’ implementations with new ones that are both faster and more accurate. He is also attempting the same for log functions. Neither PR is merged yet, so there may be unresolved performance or correctness issues.

  • Miles Cranmer has been busy modelling Julia source code in the proof assistant software Lean. It works like a kind of analytical property testing: For a method like reverse(::OrdinalRange), properties like “the input has the same number of elements as the output” are written down as lemmas together with lemmas describing its implementation, and Lean then tries to either analytically prove that the property must be correct, or else it finds a counterexample. So far, this has led to uncovering more than 400 bugs in Base (about 100 manually verified so far), and many more in packages subjected to the analysis. Miles has written a Discouse post on the subject which contains some interesting discussion. In the last few days, Miles’ AI agent has begun filing issues and PRs against Julia Base: So far, 108 issues, and 107 PRs. Now, human work is needed for reviewing these PRs to make sure the AI identified the problem correctly and found the right solution. Jameson particularly has been putting in bunch of reviews, but there is still much work to be done, and you can contribute by searching for open PRs by “MilesCranmerBot”, and taking stewardship of a PR.

  • Julia provides green-thread concurrency through the Task type, which are under conflicting demands: One one hand, tasks must “just work”, and so interact with GC and the JIT compiler, allow per-task exception handling, fork the RNG, track cancellation and much more. On the other hand, since they’re, by design, the only concurrency primitive, tasks must be lightweight. The “lightweight” part has never really been achieved. Polyester.jl provides cheap threads (get it?) by spawning a small set of Tasks and reusing them. Tasks are designed to be single-use, so Polyester achieves this by reaching into Julia internals. This causes headaches: Several packages now rely on Polyester’s speed, yet it breaks on every other Julia release. After yet another breakage. Valentin Churavy got fed up with this, and wrote ThreadTeams.jl, a new package that extends OhMyThreads.jl with Polyester-like cheap threads, except on more solid foundations. See also the discussion on Slack, where at least some Polyester’s users are looking forward to a more stable subsitute.

  • Separately, Valentin and Gabriel Baraldi are working on making Tasks faster [1, 2], but their work has not beed merged yet.

  • We’ve had const fields in mutable structs for years now (thanks, Jameson!), but remarkably, the compiler was never updated to infer :consistent or :inaccessiblememory for const field loads. Well, Cody Tapscott fixed that.

  • Julia can sometimes stack allocate Memory, but not very often, and there has long been interest in improving this. Tim Besard refactored the Memory allocation intrinsic such that the decision of whether to stack- or heap allocate happens later, which allows some LLVM optimizations to make it stack allocatable in situations it wouldn’t have otherwise. Tim also teased more work on this in the future.

  • Tim Besard has been submitting a series of PRs to improve RISCV support to Julia: [1, 2, 3, 4]. He has also made a large number of compiler fixes this month (about 50) which may or may not apply to RISCV. Julia currently has tier 3 support (meaning: limitied support, things may not work correctly) for Linux on RISCV.

  • One major limitation of trimmed binaries right now is that external libraries need to be bundled with the binary. That means you can’t just download an executable and run it - you must download a directory with the executable and a bunch of libraries. Also, the trimming process can’t see which libraries your program is using, so the bundle must include all libraries in your environment. This includes chonkers ones like BLAS, even if they’re not used. Gabriel Baraldi and Cody Tapscott has been working on improving the situation: Gabriel’s PR allows libjulia-internal to be statically linked. Cody’s (unmerged) PR allows the compiler to emit a JSON with every ccall’d library. A WIP JuliaC PR can then statically link libjulia-internal, and to remove any library not in the JSON from the bundle. Maybe in a few Julia releases, Julia apps can trimmed to single, relocatable executables?

  • Gabriel Baraldi and Kristoffer Carlsson has been working on optimizing the garbage collector, contributing around 20 fixes and optimizations the last month. I don’t have an overview of the overall impact of these contributions, as GC speed is not tracked on perf.julialang.org. Individual PRs showed great improvements in microbenchmarks, usually highlighting better behaviour in some pathological case. Shuhei Kadowaki also opened a PR that allows threads to share partially free pages, which should help with heap fragmentation, reducing memory usage.

  • reinterpret can be used to load values of type T from an AbstractArray{S}. When used on dense arrays (like Vector), it uses unsafe_load(::Ptr{T}) internally. But the compiler has trouble tracking alias information through arbitrary pointer loads and stores: How does it know that you store into only the data part of the array and don’t use the pointer to mutate the normal fields of the array, like its length? Also, using pointers require a distinct GC.@preserve for every load/store, which may hinder autovectorization. These compiler details have shown up as Base.ReinterpretArray being surprisingly slow. Andy Dienes has been working on this for some time, and now he is proposing a new pair of builtins which allow storing/loading a T from a MemoryRef{S}. This builtin will have special compiler support like the existing Core.memoryrefset!, and could be used to make reinterpret of arrays faster, as demonstrated by Andy in [1, 2, 3, 4]

  • Julia now has functions Base.Filesystem.trylockfile and Base.Filesystem.unlockfile. The former tries to lock a file returning true if the lock could be taken, or false if it could not. This API allows files to be used as locks, which allows locks between distinct Julia processes. An example use case is a command-line program where only one instance may be running at a time.

  • It was discovered that pop!(::Set) was accidentally linear instead of constant time. This was fixed by Kristoffer Carlsson by adding an extra field to Dict. It also spurred Oscar Smith to attempt a PR with a new Dict implementation, which is more similar to Python’s. However, the Dict implementation is difficult to improve on because it must be fast across a wide array of usage patterns. It’s also used to often throughout Base and the stdlibs that an implementation with compiles to more code may increase latency broadly across Julia, so code size must remain small. Finally, there is a lot of prior art on hash map implementations, which means there are many candidate implementations that must be considered. Oscars PR remains unmerged.

  • On x86 and ARM, floating point environment (“fpenv”, controlling rounding mode and which float operations cause hardware exceptions (“traps”)) is crontrolled directly by the CPU via values in special registers. The OS makes sure to track fpenv per thread. Unfortunately, that doesn’t work for Julia because Julia can schedule tasks on arbitrary threads and then migrate tasks between threads. That means, for example, a task may be spawned in one fpenv and then suddenly switch thread with another fpenv, causing float behaviour to spontaneously change from the point of view of the task. Even worse, user code may change the trap settings, and then execute code in the Julia runtime (e.g. the compiler), which may not handle these traps and so crashes. Jameson has pitched a PR to make Julia’s runtime track fpenv per task, and to always disable trapping when running code in the Julia runtime, which should solve the issue. But there is some discussion in the PR: Perhaps having fpenv a dynamic global-ish property is just fundamentally bad, broken design, and the semantics should instead happen on a per-function level (i.e. different functions, or args controlling behaviour)? Also, do we want to make Tasks even heavier and more expensive to switch by having them track fpenv? Or maybe it’s best to have Jameson’s fix in Julia for now, and then discuss better fpenv design later?

  • A series of PRs by Tim Besard [1, 2, 3 and probably more] adds profile-guided optimized (PGO) Julia builds to MacOS and Windows. PGO Linux builds were already supported back in 2024 thanks to Zentrik. PGO works by measuring a program’s execution during a real work load. These measurements can then inform the compiler how the program should be better optimized (e.g. which functions profit from inlining, how should code be layed out in the binary, etc). The program is then re-compiled with this information, which typically produces a more optimized binary. PGO builds for 1.14 are already available from juliaup using the +opt suffixes, e.g. juliaup add alpha+opt, and may be the default builds of Julia releases in the future. PGO builds has around 10% lower compile times, and so PGO is one of the larger contributions to latency reduction for Julia 1.14.

  • The implementation of === for UnionAll types is unsound due to UnionAll’s layout. UnionAll is an immutable struct containing a body and a mutable TypeVar, yet === unexpectedly computed a notion of type equivalence instead of actual object identity. Not only could that lead to the contradictory result ua1 === ua2 && ua1.var != ua2.var; it also meant the compiler was free to swap/replace two UnionAll that actually had distinct layouts. Some months ago, Keno pitched a PR trying to fix this by restructuring UnionAll to a more sensible layout. Beside fixing compiler unsoundness, hopefully this will also lead to performance improvements. The PR is large, with ~9k AI-generated LOC, and with open questions of backward compatibility due to Julia’s introspection, and so is being split up to smaller pieces that can be reviewed more easily [1, 2, 3].

  • Tim Besard has pitched a prototype PR for computed traits in Julia. The main issue it seek to solve is Julia’s monophyletic types: a fundamental problem in Julia’s type system which causes heaps of practical issues. Traits has been discussed for years, and one of the main problems has been conceiving of a trait system that works well alongside the existing type system. See also Tim’s brief design document.

Other community news

  • TensorMixedStates.jl 2.0, a rewrite of the library, simulates closed and open quantum systems with matrix product states on top of ITensor, density matrices and Lindblad equations included.

Congrats on the baby! Thanks for all the good work you’ve put in on the newsletter.

Now the question is how the AI effect, that for Julia seems to be huge (memory, size, bugs..), compare with other languages used for data analysis like Python or R..

Kristoffer Carlsson’s slimming of Julia, from 1,250 MB down to 668 MB, puts Ozempic to shame.