Julia 1.13 ships with 30% faster precompilation, redesigned REPL

Julia 1.13 has been released, and the project's own highlights post credits Ian Butterworth and "many others" for its headline performance work: packages now take roughly 30% less time to precompile than under Julia 1.12, and 10 to 20% less than 1.10, Julia's long-term-support release, depending on the machine. Startup time is about 20% faster than 1.12 too; a hyperfine benchmark comparing julia --startup-file=no -e '' on both versions measured a mean of 69.1 ms for 1.12 against 56.7 ms for 1.13, which the release notes report as 1.22 ± 0.02 times faster. The project also says it has started measuring precompile, load and execution time systematically across 39 community-submitted workflows, tracking the geometric mean on two machines; that monitoring became part of Julia's own continuous integration on September 7, 2026, running on relevant pull requests and on every commit to master, with results published at perf.julialang.org/ttfx. Measurements taken before that date were done ad hoc rather than through the new tracking.

The REPL, credited to Timothy and Kristoffer Carlsson for syntax highlighting and to Timothy for the history search, gets two visible upgrades. Typed code is now color-highlighted by default without installing the external OhMyREPL.jl package, and the default color scheme, described as conservative, can be swapped for alternatives such as Monokai. History search, entered via Ctrl-R, has been redesigned to work like the command-line fuzzy finder fzf: it supports fuzzy matching, shows which REPL mode a past command used, lets a user select multiple results to load into the prompt buffer at once, and applies the same syntax highlighting as the REPL itself; typing a question mark inside the search opens its help. Separately, bracketed paste, which lets a terminal application tell that text is being pasted rather than typed, is now available on Windows as well as the Linux and macOS platforms that already had it.

On the language side, Miles Cranmer and Jeff Bezanson added a new @FUNCTION macro that references the innermost containing function, including an anonymous one, the way the existing @MODULE and @FILE macros do for modules and files; the release notes say it should work in all kinds of functions and, unlike the internal #self# variable, is public API. Andy Dienes and Jameson Nash replaced Julia's byte-hashing algorithm with a new one called RapidhashNano, used by default for AbstractString and numeric types such as BigInt, Rational and large Real or Integer values; on a benchmark hashing a long downloaded text file, the release notes report the time falling from 8.555 microseconds under 1.12 to 1.742 microseconds under 1.13, and a custom string type that opts into the new interface goes from 204.583 to 1.750 microseconds. The move from the previous MurmurHash3-based approach to a streaming, pure-Julia implementation is presented as better on performance, readability and maintainability, and as no longer needing the input length up front. The release notes also warn that the new mixing step introduces a data dependency that can potentially lower performance when hashing elements sequentially in a tight loop, such as foldr(hash, collection), offset by unrolling the AbstractArray hashing algorithm at small to medium sizes; the default hash seed has also changed, and the notes say custom hash methods should always take the seed as an argument rather than supplying a default value for it, since the caller determines the correct seed. Separately, code-introspection macros such as @which, @code_typed and @code_warntype now accept call expressions where arguments are given as types rather than values, using the same ::T syntax as method definitions, so a frame copied from a stack trace can be pasted directly into @which; @code_typed, @code_warntype and @code_lowered now also accept broadcasting expressions.

Cody Tapscott is credited for a garbage-collection change addressing objects loaded from Julia's system image and from each package's package image: method tables, type information, compiled code and constants that are never freed and rarely mutated, but that a full garbage collection previously had to walk and mark like any other heap object. In 1.13 those objects are loaded as permanently marked so the mark phase skips them, while the rare mutations that do touch them, such as adding a method to an existing function, are tracked separately so anything new they point to still stays alive. The release notes say the result is that a full collection's cost now scales with the size of the heap a program actually created rather than with the amount of code loaded, and that incremental, young-generation collections are unaffected and equally fast on both versions. In a fresh session, a GC.gc() call is reported dropping from 0.035493 seconds to 0.000528 seconds between 1.12 and 1.13. A second example, repeatedly inserting random vectors into a Dict kept alive across five million iterations, went from 1.699095 seconds (79.80% of it spent in garbage collection) under 1.12 to 0.566276 seconds (44.32% in garbage collection) under 1.13. The release notes mention a table of full-collection times on an Apple M4 Pro across sessions with increasingly large packages loaded.

Kiran Pamnany, Jameson Nash and Ian Butterworth are credited for a set of scheduler fixes. Idle threads now park in a dedicated scheduler task instead of holding on to the last task they ran, so finished tasks can be garbage-collected promptly, and several lost-task and deadlock races were fixed. Interrupts are reliable again: Ctrl-C now reaches user code, including scripts blocked in sleep or I/O, and Distributed.interrupt works. @spawn now wakes only one idle thread in a task's threadpool instead of every thread, which the release notes say speeds up spawn-heavy code anywhere from no change at all on macOS, to 1.1 to 1.6 times on a 16-core Linux machine, to 10 to 300 times on Windows and heavily oversubscribed machines, where waking every thread had previously been the dominant cost. A proper task-cancellation mechanism is described as work in progress, planned for Julia 1.14.

Ian Butterworth is also credited for a new --trace-eval command-line flag that prints top-level evaluation progress, useful for spotting where a script or test suite hangs, and which turns on automatically when a CI run has GitHub Actions' debug-logging option enabled. Cody Tapscott and "many others" turned the repository's juliac.jl script into a standalone package and application, JuliaC.jl, which can now trim more from a compiled binary, including finalizers, @cfunction and mapreduce, alongside fixes to bugs in the trimming process itself. Kristoffer Carlsson is credited for changes to Julia's package manager, Pkg, the most notable being that downloads from a package server, covering registries, packages and artifacts, now default to a zstd-compressed archive instead of a gzipped one; the release notes say zstd tends to offer both a better compression ratio and significantly better decompression performance for the kind of files Pkg downloads, illustrated with figures for downloading the Plots, Makie and ModelingToolkit packages. The release notes describe further resolver and registry micro-optimizations improving Pkg's general performance.

Key facts

  • Package precompilation is roughly 30% faster than Julia 1.12 and 10 to 20% faster than 1.10, the long-term-support release; startup time is about 20% faster than 1.12, measured at 56.7 ms versus 69.1 ms in a hyperfine benchmark.
  • The REPL now has built-in syntax highlighting without needing an external package, plus a redesigned Ctrl-R history search that works like the fzf fuzzy finder, supports selecting multiple results, and shows which REPL mode each past command used.
  • A garbage-collector change that permanently marks sysimage and package-image objects cuts a fresh-session GC.gc() call from 0.035493 to 0.000528 seconds, and drops a Dict-insertion benchmark from 1.699095 seconds (79.80% of it in GC) to 0.566276 seconds (44.32% in GC).
  • Scheduler fixes make Ctrl-C interrupts reliable again and have @spawn wake only one idle thread instead of every thread, speeding spawn-heavy code by 1.1 to 1.6 times on a 16-core Linux machine and 10 to 300 times on Windows and heavily oversubscribed machines.
  • The default hash algorithm switches from a MurmurHash3-based approach to RapidhashNano, cutting the time to hash a long string from 8.555 to 1.742 microseconds, and Pkg now defaults to zstd-compressed downloads instead of gzip.

Why it matters

Julia 1.13's headline numbers speak to a pain point the release notes name directly: time to first X, the wait between starting Julia and getting a first result, made up of precompiling, loading and running code. Cutting precompilation by roughly 30% against 1.12 and 10 to 20% against 1.10, the long-term-support release, plus a further 20% off startup time, chips away at that wait for anyone running Julia interactively or in short scripts. The release notes also present this as more than a one-off optimization pass: since September 7, 2026, time-to-first-X measurements run automatically in Julia's own continuous integration, on relevant pull requests and on every commit to master, with results published at perf.julialang.org/ttfx, so future regressions should surface in CI rather than only after a release ships. The garbage-collector change matters for a related reason: the release notes say sessions that load a handful of large packages previously paid a full-collection cost that scaled with the amount of code loaded rather than the size of the heap a program actually created; their own Dict-insertion example shows the benchmark's total run time falling from 1.699095 seconds (79.80% of it in garbage collection) to 0.566276 seconds (44.32% in garbage collection).

Who it affects

Anyone running Julia gets the precompile, startup and REPL changes without altering any code. Windows users see two specific gains that Linux and macOS users already had, or benefited from less: bracketed paste in the REPL, and, for heavily multi-threaded or oversubscribed programs, a 10 to 300 times speedup from the @spawn scheduler fix, compared with 1.1 to 1.6 times on a 16-core Linux machine and no measurable change on macOS. Anyone with a custom hash method for their own type needs to check it: the default seed has changed, and a method that hardcodes a default value for the seed argument, instead of always taking it as a caller-supplied argument, runs against the release notes' own guidance. Users of Distributed.interrupt and anyone who relies on Ctrl-C get a scheduler that the release notes say makes interrupts reliable again. Anyone downloading packages from a registry, artifact or package server is affected by the Pkg change, since those downloads now default to zstd compression instead of gzip.

How to use it

None of the highlighted precompile, startup, garbage-collection or scheduler improvements need an opt-in, a source change or an extra package to take effect. The REPL's syntax highlighting and its redesigned Ctrl-R history search work by default, with the highlighting color scheme customizable per the REPL documentation, and a question mark typed inside history search opening its own help. The new --trace-eval flag is run from the command line, for example "julia --trace-eval script.jl", to print each top-level evaluation as it happens, and switches on automatically when a CI run has GitHub Actions' debug-logging option enabled. The juliac.jl trimming script is now the separate JuliaC.jl package, so anyone who used the old in-repo script should move to it. Anyone defining a custom hash method should write it as hash(x::MyType, h::UInt) and never give the seed argument a default value, since Julia itself supplies the correct seed at the call site.

How solid is it

This account is drawn from the Julia project's own release-highlights post at julialang.org, a primary source rather than third-party reporting. It backs its performance claims with runnable benchmark commands and their output: hyperfine output for the startup comparison, @btime output for the two hashing comparisons, and @time GC.gc() output for the garbage-collector comparison. Most highlighted features in the post are credited to named contributors; bracketed paste on Windows and the code-introspection macro changes are not. The Hacker News discussion of the post had drawn 232 points and 21 comments at the time of writing. The systematic time-to-first-X tracking the post cites is itself new, live only since September 7, 2026; by the post's own account, measurements before that date were ad hoc.

Risks and caveats

Some of what shipped is explicitly incomplete rather than finished: the release notes describe proper task cancellation as work in progress, targeted for Julia 1.14, not delivered in 1.13. The new hash algorithm's mixing step trades one thing for another: the release notes say it introduces a data dependency that can potentially lower performance when hashing elements sequentially in a tight loop, such as foldr(hash, collection), even though hashing whole arrays is unrolled and faster at most lengths. The default hash seed has also changed; the release notes' own reminder is that custom hash methods should never hardcode a default value for the seed, since the correct one is supplied by the caller.

“The cost of a full collection now scales with the size of the heap that your program actually created, not with the amount of code that has been loaded.”

— Julia 1.13 release notes