# Can we have non-blocking precompilation? 🙏

**URL:** <https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083>\
**Category:** Internals & Design\
**Tags:** precompilation\
**Created:** [July 11, 2026, 4:09am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083 "2026-07-11T04:09:16Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 4:09am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/1 "2026-07-11T04:09:16Z")

</div>

Can we have non-blocking precompilation? I think this would be great.

So, currently, when I type `using MyPackage` at the REPL and the cache is stale, I have to sit through precompilation before I can touch anything in `MyPackage.*`. But, precompilation only really pays off the _next_ time I load the package. Julia can already load packages without caches at all (`--compiled-modules=no`), so in principle the REPL could give me the package immediately, with full JIT compilation as I go, while precompilation runs in a background process for next time.

Consider two workflows:

1. **REPL.** I want the fastest possible time-to-first-input for a newly installed package. I don’t care about eating some extra JIT compilation this session, and I would still benefit from whatever caches already exist. I just do not want to wait up front for caches that only help future me, when current me is just trying to run something.
2. **Scripts.** For a re-runnable script, using the caches matters more. But even then: if the cache is stale when the script starts, why must the whole precompile finish before line one runs? The script could run uncached now while precompilation happens in the background, and the next invocation gets the warm start.

I know Pkg already precompiles eagerly after `Pkg.add`/`instantiate`, which hides the wait for freshly installed packages (though I wish this was also non-blocking). The case I keep hitting is everything else: a package I just edited, a one-off install to do something, a changed Project.toml, a single changed dependency version. Then I have to wait on `using`.

Now, the obvious tradeoff is paying twice: the first session JIT-compiles some stuff that the background precompile is also compiling. I think it’s worth it though. Maybe the desire is for background jobs to not compete for cores, but I feel like the user’s focus time is more valuable.

So: is there a fundamental reason blocking precompilation is the default, or maybe just that nobody has built it yet? I think it would be pretty nice!

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 11, 2026, 8:07am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/2 "2026-07-11T08:07:24Z")

</div>

The immediate problem is there’s no firm line between the module you want immediately and the part you’re calling precompilation. Precompilation caches things during the evaluation of the module in a worker process unbiased by the current session’s state, then the cache _might_ be loaded into the current session (next paragraph for more thoughts). There isn’t a module evaluation phase followed by a module precompile phase; we can obviously put function calls and `precompile` calls between methods (ideally the further changes to world age wouldn’t invalidate). PrecompileTools.jl isolates a precompile phase by only running its setup and workload blocks when precompilation occurs, but even that is strictly within the `module` block and can occur before other expressions. Note that doesn’t apply to the plain function calls and `precompile` calls that run regardless of precompilation. That could be addressed by offering `PrecompileTools`’ tricks as a feature, but people would have to manually opt into them and could have good reason not to.

Another problem is module inconsistency. We already observe this when a package and its dependencies are precompiled, but we get a warning that different versions of some dependencies are already loaded from another environment or a prior environment state. We either restart the session or put up with more precompilation we’d probably only use for that session’s weird state. You’re at least skipping the precompilation for the current session, but you’re embracing the same risk of the active module being different from the precompiled module loaded by the next session. Since you’re not waiting for precompilation, you don’t get that warning until after you do some work in the probably wrong environment, and it’s not clear where that warning could interject. This could be solved by getting the version warnings after the module is evaluated and before the worker processes make caches, then we could choose to call `exit()` and wait for the workers to finish before the session really ends.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 8:19am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/3 "2026-07-11T08:19:27Z")

</div>

Thanks, that’s helpful. Looking at this now. My thought for the first issue was to load the module normally from source in the foreground, while a separate standard precompile worker independently evaluates it and writes a cache only for a future session; the current session would simply never adopt that cache.

For the version-consistency warnings, would it make sense to capture the worker’s diagnostics and surface warnings asynchronously (or at exit), while remaining quiet on success? Or do you think waiting for workers at exit is necessary?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 8:22am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/4 "2026-07-11T08:22:56Z")

</div>

P.S., here is what I (and my bot) cooked up so far in case you were curious: [Comparing JuliaLang:master...MilesCranmerBot:feature/nonblocking-precompilation · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/compare/master...MilesCranmerBot:julia:feature/nonblocking-precompilation)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 11, 2026, 8:34am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/5 "2026-07-11T08:34:12Z")

</div>

> [@MilesCranmer](#):
>
> My thought for the first issue was to load the module normally from source in the foreground, while a separate standard precompile worker independently evaluates it

That’s more of the premise than addressing the first issue. To put it another way, the first issue is that evaluating the module itself can take a long time and `PrecompileTools` only isolates what it currently does. We’d need new features to push the rest to precompile-time (and ironically this would disproportionately involve the devs who intentionally shifted to lists of `precompile` statements to save the call execution time in `PrecompileTools` workloads), and that may not be feasible for some things e.g. conditional method definition that needs a very time-consuming check.

> [@MilesCranmer](#):
>
> For the version-consistency warnings, would it make sense to

I’d want the warning right when I get the module so I can decide what to do with it. Figuring out the version clashes before making caches would be the time-saver. Waiting for workers at `exit()` is just my assumption that the session has to stay alive to not kill the workers; we do want those precompile caches next session.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 8:42am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/6 "2026-07-11T08:42:47Z")

</div>

Oh I see, you’re talking about making module _evaluation_ non-blocking? This is different from what I meant: I only mean backgrounding precompile-cache generation. Evaluating the module would still happen normally in the foreground.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 11, 2026, 8:59am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/7 "2026-07-11T08:59:11Z")

</div>

Not at all, the point is to get the module for the session, not for the session to skip it. I’m talking about skipping more than just the `PrecompileTools` workloads so we actually get the bare minimum module. If I provided a package with very time-consuming `precompile` calls and no `PrecompileTools` workloads to your proposed system, the current session’s module would take just as long to evaluate as the next session’s precompiled module. Longer to us, because the worker processes can at least work on dependencies in parallel.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 9:38am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/8 "2026-07-11T09:38:34Z")

</div>

Does `--compiled-modules=no` already skip the precompilation-only work you have in mind? If so, I guess I might expect `--compiled-modules=background` to use the same foreground-loading behavior while generating the cache separately in the background. Not sure though.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [July 11, 2026, 9:48am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/9 "2026-07-11T09:48:03Z")

</div>

> [@MilesCranmer](#):
>
> Can we have non-blocking precompilation?

You mean [precompilepkgs: optionally run precompilation in background task with keyboard controls - Pull Request #60943 - JuliaLang/julia - GitHub](https://github.com/JuliaLang/julia/pull/60943)?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 9:49am UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/10 "2026-07-11T09:49:16Z")

</div>

See [Can we have non-blocking precompilation? 🙏 · Issue #62337 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/62337#issuecomment-4943758628) - that PR is only Pkg rather than loading.

I think the branch I shared above uses the same function created from that PR?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 12:08pm UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/11 "2026-07-11T12:08:21Z")

</div>

Ok it seems to be working!

> <https://github.com/JuliaLang/julia/pull/62340>
>
> Fixes #62337 
> 
> This PR adds a new \`--compiled-modules=background\` mode. If a v…alid compilation cache exists, Julia loads it as usual. If the cache is missing or stale, Julia instead loads the package from source and generates the cache in the \_background\_ for the next Julia process. In other words, the first load behaves similarly to \`--compiled-modules=no\`, without giving up compilation caches on future loads.
> 
> The main motivation is interactive use. Currently, a stale cache makes \`using Foo\` wait for precompilation even though that cache only benefits future sessions. With this mode, \`using Foo\` returns after loading \`Foo\` from source, while the existing precompilation machinery handles the cache separately. This trades some duplicated compilation work for getting control of the REPL back sooner.
> 
> Multiple \`using\` calls share the same background precompile session when possible, and existing valid caches are still used. Cache generation is best-effort: if the existing background session cannot accept another package, that package still loads normally and a later Julia process can try generating its cache again.
> 
> The automatic background job is silent so that it does not print over the REPL. If desired, \`Base.Precompilation.monitor\_background\_precompile()\` can be used to attach to the current job and wait for it.
> 
> This uses the same mechanism as in #60943 @IanButterworth.

I need to stop nerd sniping myself like this 😪

---

<div class="post-metadata">

**Author:** ![jondea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jondea/32/39086_2.png) [@jondea](https://discourse.julialang.org/u/jondea)\
**Post date:** [July 11, 2026, 2:00pm UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/12 "2026-07-11T14:00:37Z")

</div>

This is a great idea! Should it be the default for interactive REPLs?

---

<div class="post-metadata">

**Author:** ![franckgaga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/franckgaga/32/218241_2.png) [@franckgaga](https://discourse.julialang.org/u/franckgaga)\
**Post date:** [July 11, 2026, 2:18pm UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/13 "2026-07-11T14:18:13Z")

</div>

I think yes! 💯

But it’s presumably highly experimental for now, hence include non-blocking precompilation in a future Julia release, but disabled by default in the REPL.

---

<div class="post-metadata">

**Author:** ![MDSW](https://avatars.discourse-cdn.com/v4/letter/m/94ad74/32.png) [@MDSW](https://discourse.julialang.org/u/MDSW)\
**Post date:** [July 11, 2026, 2:39pm UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/14 "2026-07-11T14:39:27Z")

</div>

The parallel question is, should it be the default for _agentic_ sessions? The broader discussion of this is for a separate thread, but the work described here is very timely and responsive to some of the challenges noted in this [cautionary story from the Haskell world](https://avi.press/posts/2026-07-10-after-7-years-in-production-scarf-has-reluctantly-moved-away-from-haskell.html), in particular the compile feedback cycle time. We should have this additional context in mind as we add improvements such as this.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 11, 2026, 8:08pm UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/15 "2026-07-11T20:08:58Z")

</div>

> [@MilesCranmer](#):
>
> Does `--compiled-modules=no` already skip the precompilation-only work you have in mind?

No, because there’s nothing that specifies that work to only occur at precompile-time. `--compiled-modules=background` can’t do anything about that either, it just sounds a lot more useful so it’s worth bringing up the unskippable “precompilation” (maybe this should just be called module evaluation-time compilation).

This would require another feature that developers of the package and all its dependencies need to opt into. Now I think about it, throwing `precompile` calls into `@compile_workload` blocks might actually work, but a different option is needed for direct top-level calls to only cache package-owned signatures.

> [@jondea](#):
>
> Should it be the default for interactive REPLs?

I hope not, I’d typically rather wait upfront and take a break than to spread TTFX across separate manual calls. I might want a uncached package if I was developing it across sessions, but I could also just omit its precompile files and may want to precompile its mostly unchanged dependencies (`--compiled-modules=existing` has a similar purpose, but it still runs unskippable precompilation and won’t precompile dependencies). Could be nice to have a manual `@futurecache using Package`.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 11, 2026, 8:53pm UTC](https://discourse.julialang.org/t/can-we-have-non-blocking-precompilation/138083/16 "2026-07-11T20:53:46Z")

</div>

At the risk of wading into a subjective defaults war (fun!), even though the PR makes it non-blocking precompilation opt-in (please note!), I also personally think it would be more ergonomic to have the behavior be opt-out at some point in the future.

Then, if someone did in fact want to wait, they could run `Pkg.precompile()` to get it immediately, or `Base.Precompilation.monitor_background_precompile()` to wait on the background one (exists from the Pkg feature).

(And I know the canonical local fix will be something like “_just set these three 20-character environment variables to 0, sacrifice a goat, and Julia will maybe sometimes skip the century-long precompilation of the complete transitive dependency graph of human civilization because of a changed docstring, all so you can make a log-log plot for a lecture._”… but I am not a fan).

Also, backgrounded precompilation might improve TTFX depending on call, see [Add `--compiled-modules=background` for non-blocking precompilation - Pull Request #62340#issuecomment-4946212900 - JuliaLang/julia - GitHub](https://github.com/JuliaLang/julia/pull/62340#issuecomment-4946212900). I guess it’s the same for the existing `--compiled-modules=existing`, only that `--compiled-modules=background` also triggers a cache for next time you start! Therefore the `background` option seems capable of graduating to an always-on default at some point in the future. (Not now, please note!)
