# I find it hard to develop in Julia

**URL:** <https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497>\
**Category:** Internals & Design\
**Created:** [February 6, 2026, 11:25am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497 "2026-02-06T11:25:19Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [February 8, 2026, 12:37am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/41 "2026-02-08T00:37:15Z")

</div>

I remain optimistic that the existence of `Base.ispublic` will slowly but surely improve the state of affairs. Prior to 1.11, it was really difficult (borderline impossible at times) to know if something was considered public or private.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 8, 2026, 2:40am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/42 "2026-02-08T02:40:21Z")

</div>

> [@adienes](#):
>
> Prior to 1.11, it was really difficult (borderline impossible at times) to know if something was considered public or private.

I think the general rule was that anything exported or documented in the manual was public, and everything else was private?

The `public` keyword gave us a programmatic way of detecting whether a non-exported symbol is public. Unfortunately, it also helped turn up some cases of undocumented public/exported symbols: [Missing docstrings for public/exported symbols · Issue #52725 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/52725)

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [February 8, 2026, 3:58pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/43 "2026-02-08T15:58:33Z")

</div>

> [@stevengj](#):
>
> Unfortunately, it also helped turn up some cases of undocumented public/exported symbols:

Why unfortunately? That’s good right?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 8, 2026, 5:37pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/44 "2026-02-08T17:37:34Z")

</div>

It’s good that we found them—this is indeed a benefit of the `public` keyword—but it is unfortunate that the omissions existed in the first place.

(This is a “help wanted” issue, by the way: it should be relatively easy to contribute missing docstrings.)

---

<div class="post-metadata">

**Author:** ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)\
**Post date:** [February 8, 2026, 8:50pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/45 "2026-02-08T20:50:42Z")

</div>

But, at least anecdotally, it seems like many packages break after upgrading to a new Julia version. I am still on 1.11 since a bunch of my stuff broke on 1.12. Are packages really use that many undocumented functions? Or do the internals change significantly?

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [February 8, 2026, 8:57pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/46 "2026-02-08T20:57:35Z")

</div>

> [@affans](#):
>
> Are packages really use that many undocumented functions? Or do the internals change significantly?

yes to the former, many packages use internals they “shouldn’t” all the time. for the latter in the case of 1.12 there were also quite significant internal changes to accommodate all the binding partition (const / struct redefinition) stuff.

another example of packages relying on things they shouldn’t that will almost certainly break things on 1.13 is that most hash values will change. even though the docs specifically have warnings to call this out as a possibility, in practice hash values have been very stable for a long time and some packages have come to rely on them.

---

<div class="post-metadata">

**Author:** ![JamesNZ](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jamesnz/32/35361_2.png) [@JamesNZ](https://discourse.julialang.org/u/JamesNZ)\
**Post date:** [February 8, 2026, 9:12pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/47 "2026-02-08T21:12:58Z")

</div>

> For a longer time, my main hope has been that Tim Holy has stated improvements on Julia’s lowering mechanism could bring one or more order of magnitude improvements to the speed at which Julia can be interpreted.

Another possible solution is tiered compilation. No idea how much work it is (probably a lot…) but it would be really nice to have. Maybe it’d even be possible to have interpretation be the first tier if that’s faster than `-O0` or whatever.

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [February 9, 2026, 7:46am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/48 "2026-02-09T07:46:54Z")

</div>

Interesting discussion, @fonsp! I empathize with your pain from new Julia releases, but I can’t say I share it.

I maintain around 10 Julia packages, and most releases don’t require any work from my side to keep those packages working. Granted, the packages are smaller than Pluto, but still, my experience with Julia’s (in)stability is completely different than yours. In fact, I find developing in Python to be far more precarious at new releases!

Why the different experiences? I think this sentence of yours is the answer:

> When I struggle with the developer experience of Julia, I am sometimes left feeling like this was somehow _my fault_. I used the API wrong (but there was no clear documentation). I used internal API (because there was no public API).

Internal APIs are going to change. By definition. If you build a package on top of internal APIs, you’re asking for breakage. I’m sorry to put it this bluntly, but if _this_ is why Pluto.jl keeps breaking, then it’s entirely your fault.

On some level, the discussion could be closed at that, but there are some nuances that are worth discussing.

### Are new Julia releases really worth it?

Maybe. The latency has gotten worse the last three of Julia releases (including 1.13).  
Since latency is possibly the single worst thing about Julia, it’s reasonable to conclude that newer Julia releases are, on balance, worse, and therefore they are not worth it, even if they caused _no_ code to break.

So, the latency regressions are bad, I think we all agree on that. But new Julia releases have given us lots of great features: `Memory`, Pkg apps, Project `[sources]` section, Manifest versioning, trimming, struct revision (even as that is still quite poor), OncePerProcess, `public` keyword, new atomic operations, and scoped values. And that’s just the last two releases!

### Is it too hard to avoid Julia “internals”?

There is some argument to be had that it’s too easy to **accidentally** rely on Julia internals:

For example, there is no warning when accessing internal symbols, and it’s not clear when reading source code what is internal and what isn’t. Accessing fields of public structs is also typically considered internals, but there is no warning of that, either. Neither is the fact that iterator states is a private detail.

More generally, the behaviour of Julia functions is underspecified, which makes it too easy to accidentally rely on internal behaviour, and what is considered “breaking” in Julia is too often a matter of norms.

Hypothetically, would it be breaking if `length(::Vector)` began returning `UInt`? Obviously, that would be breaking. Right?

But why? That is, by _what rule_ is this breaking? I don’t think it’s documented anywhere that it returns an `Int`. A `UInt` would still be semantically correct. And plenty of Julia releases has changed the output type of a function. For example, would it be breaking for `map(abs, UInt(1):UInt(2))` to return `UInt(1):UInt(2)`? What if I make my own `MyVector` - would adding a specialized method `map(f, ::MyVector)::MyVector` be breaking?

And that’s before I get to functions are types that are so underdocumented that you literally can’t use them, because they have almost no documented behaviour, and therefore _nearly all use of them is absuing internal_.

If _those_ kinds of breaking changes are the reasons that Pluto breaks on minor releases, then the breakage isn’t defensible. It’s just painful and I completely get your frustration.

If that’s the case, I very much encourage you to make a new topic and discuss the underspecified behaviour that caused breakage. I think you would do the community a service to state your troubles precisely - the responses in this thread makes it clear that we’re not quite clear whether Pluto breaks because you used internal functions, or relied on the observable but undocumented behaviour of a public, underdocumented function.

### Did we make a mistake **allowing** people to use internals?

I’m tempted to draw the most misanthropic conclusion from the above: People can’t handle the ability to access internals, and will abuse it relentlessly before complaining when their code break, so we should never have allowed people to access internals in the first place. People clearly can’t be responsible on this.

The times I’ve been trolling through PkgEval and been looking at failures, I’ve certainly seen my share of authors using blatantly internal functions, and even more than once an author being dismayed or even surprise that the devs dared to change the metaphorical `Core.__unsafe_internal_write!`.

Where Python is explicit about its “consenting adults” principle, perhaps Julia should have been like Java or Rust - no `public`, no usage?

The counter-argument is that if Julia was like that, we wouldn’t have had great packages like LoopVectorization, Casette, Pluto, Mooncake, or Zygote, which only work by hooking into Julia internals.

Then again, the historical survival rate of these projects is abysmal. In effect, we _don’t_ have projects like that anyway, because they keep dying (having used up community development resources in the meanwhile).

### What could a better system look like?

Of course the following is way too late - Julia is not at that stage of development anymore etc etc, but at least I find it _interesting_ to think how this internals abuse could be mitigated by language design. One could go the well-trodden route of _disallowing_ access to internals - but is that really a good idea? In science, I sometimes want to pick apart someone else’s code and dig into internals to run some non-standard analysis. This is fine as long as I’m responsible to ensure the internal abuse is functioning correctly, and _I’ve pinned the version_ of my dependency. I think it would be a shame to completely remove the ability to do this.

Perhaps we should take inspiration from how Rust handles unsafe code: It requires specific functions, as well as an `unsafe_` block which can be grepped for, and even statically disallowed in projects.

Julia could have had a `using internals Base: foo, bar` statement. Without `using internals`, internal names would not be importable at all. Then, the General Registry could scan source code for `using internals SomePackage`, and refuse entry of a package into the registry unless SomePackage was set to a precise version in the Project.toml.

Similarly, `getproperty` could be unusable on foreign types unless explicitly implemented.

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [February 9, 2026, 9:53am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/49 "2026-02-09T09:53:16Z")

</div>

I have to second Jakobs points here. I develop a few packages – certainly far far away from the popularity of Plutos – but I did not yet run into the problem that a release broke one of my packages.

On the other hand I do see that sometimes it might be necessary to use functions / features in Julia that might be considered internal. Or one uses them “by accident” thinking they would not break. Then it is of course frustrating. So getting a clear distinction on that is probably good to have.

---

<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:** [February 9, 2026, 10:03am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/50 "2026-02-09T10:03:59Z")

</div>

The internal API point is fair but I also find that for many things I want to do in Julia, there is just no public API alternative. If we measured of how many of the most popular Julia libraries relied on non-public methods, I’m guessing it would be a decent fraction. But it may very well be that Julia, by being a very flexible interactive language with its stdlib written in the same language, ends up leading people down a path of diving into the internals… 🤷

> [@giordano](#):
>
> However we eventually had a much better experience lately when, instead of fighting every single version of Pkg, we had a discussion with the Pkg developers to have a set of tests in Pkg representing the BinaryBuilder.jl’s Pkg workload, after getting help from them to clean up the use of the Pkg API inside [BinaryBuilder.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/BinaryBuilder).

On this point, the same way that Julia now tests against Revise.jl to avoid breakages there, I wonder if there could be a “PkgEvalMini” for running PkgEval against a small subset of the most popular packages in the ecosystem. PkgEval is so large that it is only used sparingly, and isn’t necessarily a clean signal. A smaller, “most important package” integration suite might be useful

---

<div class="post-metadata">

**Author:** ![j-fu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/j-fu/32/11373_2.png) [@j-fu](https://discourse.julialang.org/u/j-fu)\
**Post date:** [February 9, 2026, 11:44am UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/51 "2026-02-09T11:44:41Z")

</div>

Now that we have `public` and tooling like ExplicitImports.jl I think the way forward here is to identify uses of non-public internals and start a discussion between package developers and Julia core devs. IMHO there are several options for particular internal function:

- Can it just be made it public ? (this would include adding docstrings and unit tests)
- Is there a way to create a wrapper API as part of core Julia around internal functionality which is needed by e.g. Pluto ?
- Are there other ways for implementing certain features, without accessing internals ?

So that we slowly can move to develop a stable API to provide functionality which in the moment is only available by using internals.

---

<div class="post-metadata">

**Author:** ![TimG](https://avatars.discourse-cdn.com/v4/letter/t/82dd89/32.png) [@TimG](https://discourse.julialang.org/u/TimG)\
**Post date:** [February 9, 2026, 12:20pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/52 "2026-02-09T12:20:32Z")

</div>

> [@jakobnissen](#):
>
> if _this_ is why [Pluto.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/Pluto) keeps breaking, then it’s entirely your fault.

I don’t think this is quite as black and white as you suggest. I am writing an excel backend for PrettyTables. To do so in a way that is functionally complete, I need to be able to write StyledStrings into Excel cells. This simply isn’t possible unless I access StyledStrings internal. So I have a simple choice. Either I don’t provide the functionality at all, or I need to set myself up for breaking changes in future which are “my fault”. This seems sub-optimal somehow.

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [February 9, 2026, 12:22pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/53 "2026-02-09T12:22:54Z")

</div>

> [@jakobnissen](#):
>
> There is some argument to be had that it’s too easy to **accidentally** rely on Julia internals:

In my experience, it’s not just easy, but is also _a standard practice_ even followed by the Julia itself. I’ve noted previously in this thread my pain with the tracking allocations in Julia so I will give a concrete example.

Let’s check the documentation of the `@allocations`, ok, good, fine, clear. It works, until [it doesn’t](https://github.com/julialang/julia/issues/58780). Apparently, such a simple thing can be underspecified and actually even [not recommended](https://github.com/JuliaLang/julia/issues/58780#issuecomment-2992349477) (what??? how would I know that from the documentation?). What can semantically be more easier than telling me if my function is allocating or not, that it can actually change behavior…

Anyway, people suggest ([somewhere in some discussion on GitHub](https://github.com/JuliaLang/julia/issues/58780#issuecomment-3178381507) that you’re supposed to know about of course) to look into `@timed`. Fine, let’s check the documentation for `@timed`.

```julia-auto
help?> @timed
  @timed

  A macro to execute an expression, and return the value of the expression, elapsed time in seconds, total bytes allocated, garbage collection time, an object with
  various memory allocation counters, compilation time in seconds, and recompilation time in seconds. Any lock conflicts where a ReentrantLock had to wait are
  shown as a count.

  In some cases the system will look inside the @timed expression and compile some of the called code before execution of the top-level expression begins. When
  that happens, some compilation time will not be counted. To include this time you can run @timed @eval ....

  See also @time, @timev, @elapsed, @allocated, @allocations, and @lock_conflicts.

  julia> stats = @timed rand(10^6);
  
  julia> stats.time
  0.006634834
  
  julia> stats.bytes
  8000256
  
  julia> stats.gctime
  0.0055765
  
  julia> propertynames(stats.gcstats)
  (:allocd, :malloc, :realloc, :poolalloc, :bigalloc, :freecall, :total_time, :pause, :full_sweep)
  
  julia> stats.gcstats.total_time
  5576500
  
  julia> stats.compile_time
  0.0
  
  julia> stats.recompile_time
  0.0

```

Do you see something strange? Does the official documentation “hacks” into the `stats.gcstats` with `propertynames` and suggest me this is how to use it? What is `gcstats.pause`? What is `gestates.allocd`? Is it a short name for **alloc** ate **d**? Or it is an allocation Daemon? I can’t believe `allocd` is the amount of allocated memory when I do a simple test:

```Julia
julia> e = @timed 1 + 1
(value = 2, time = 3.333e-6, bytes = 432, gctime = 0.0, gcstats = Base.GC_Diff(432, 0, 0, 8, 0, 0, 0, 0, 0), lock_conflicts = 0, compile_time = 0.0, recompile_time = 0.0)

```

Further. What is `freecall`? What is even `total_time` suggested by the documantation? Is it time spent during GC? Is it time from `@timed`? What is `full_sweep`? I can certainly know that by looking into the documentation of gc stats, right? Right?

```julia-auto
help?> Base.GC_Diff
  │ Warning
  │
  │ The following bindings may be internal; they may change or be removed in future versions:
  │
  │ • Base.GC_Diff

  No documentation found for private binding Base.GC_Diff.

  Summary
  ≡≡≡≡≡≡≡

  struct Base.GC_Diff

  Fields
  ≡≡≡≡≡≡

  allocd :: Int64
  malloc :: Int64
  realloc :: Int64
  poolalloc :: Int64
  bigalloc :: Int64
  freecall :: Int64
  total_time :: Int64
  pause :: Int64
  full_sweep :: Int64

julia> 

```

Yeah, not very helpful. So in the doctoring of `@timed` I’m encouraged to hack around with `propertynames` and figuring out what actually is going on with this struct and how to use `@timed`. And since `@allocations` is [not recommended](https://github.com/JuliaLang/julia/issues/58780#issuecomment-2992349477) and `@timed` [is recommended](https://github.com/JuliaLang/julia/issues/58780#issuecomment-3180273883) this is the way I guess. And since Julia suggest to do that then people actually start doing that as their standard routine.

And this is just one simple example. It happens like pretty much all the time when Julia leaks its own internal implementation details and then the response is that we shouldn’t rely on it. And since this is happens all the time people just get used to that and it becomes “the norm”.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [February 9, 2026, 12:27pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/54 "2026-02-09T12:27:12Z")

</div>

For the allocations I currently changed to use `Chairmarks.@b`, which is fast and, I guess, reliable.

Can this part of the discussion be split into a different topic? I think it is a common issue in 1.12 but does not exactly has to do with the original discussion, as this breaks a test, not really the packages.

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [February 9, 2026, 12:35pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/55 "2026-02-09T12:35:08Z")

</div>

I agree with you that its off-topic and the allocations issue better be discussed somewhere else. I just used it as an example to show that relying on internals is standard practice even within Julia official docs and the focus is on the documentation, not the allocations issue.

Your example with Chairmarks [also relies on the same internals](https://github.com/LilithHafner/Chairmarks.jl/blob/52678207dfb4b4ca7ba33fa4a224d13c1acde4c2/src/benchmarking.jl#L169), which proves the point. So `Chairmarks` is going to be broken as soon as `Base.GC_Diff` will be changed or Base decides to remove `Base.gc_alloc_count` because both are private internals.

---

<div class="post-metadata">

**Author:** ![mihalybaci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mihalybaci/32/13528_2.png) [@mihalybaci](https://discourse.julialang.org/u/mihalybaci)\
**Post date:** [February 9, 2026, 1:08pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/56 "2026-02-09T13:08:26Z")

</div>

> [@TimG](#):
>
> This simply isn’t possible unless I access StyledStrings internal. So I have a simple choice. Either I don’t provide the functionality at all, or I need to set myself up for breaking changes in future which are “my fault”.

A third option, as @giordano brought up for his package, would be to talk to the developers and open an issue with StyledStrings and request they make that particular internal code part of the public API. If you are you using it already, then you might even be the best person to write the PR in a way that will not break your code in the future.

---

<div class="post-metadata">

**Author:** ![TimG](https://avatars.discourse-cdn.com/v4/letter/t/82dd89/32.png) [@TimG](https://discourse.julialang.org/u/TimG)\
**Post date:** [February 9, 2026, 1:25pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/57 "2026-02-09T13:25:07Z")

</div>

The functions I need already exist in the case of StyledStrings and were suggested for my use by the package author. But they aren’t part of the public API at the moment - though that may, of course, change in future.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 9, 2026, 2:08pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/58 "2026-02-09T14:08:35Z")

</div>

> [@jakobnissen](#):
>
> Where Python is explicit about its “consenting adults” principle, perhaps Julia should have been like Java or Rust - no `public`, no usage?

I think this can be handled in a softer way by tooling, eg we already have the excellent ExplicitImports.jl, and once

> <https://github.com/JuliaTesting/Aqua.jl/issues/268>
>
> One of my packages broke because of
> 
> \`\`\`julia
> using Base.Iterators: countfrom…, repeat
> \`\`\`
> 
> As of Julia 1.9, \`repeat\` is no longer available that way, and I didn't notice that it was in Base all along.
> While checking the other imported identifiers, I noticed some other candidates that didn't even need anymore.
> It would be awesome if Aqua could detect those.

is solved it will be integrated automatically into a lot of workflows that use Aqua already.

That said, I think that packages which use internals do it on purpose, not accidentally, and most packages which do it make this very explicit.

About the OP: I mostly experience breakages with packages that reach into the internals up to their imaginary elbows, mostly AD. But they are also mostly very good at communicating this, eg if you try Enzyme.jl on the (yet) unsupported versions, you get warnings.

I agree with those who point out that in the long run, the solution is to factor out those internals to public APIs. However, this is usually takes long since API design is difficult, and people want to get it right if it is to be included in the Julia API.

Experience shows that the best compromise may be a “shim” package that is not officially part of Julia, and contains branching codepaths for various versions, while presenting a consistent interface. This allows experimentation with the API (easier to release a 2.0 than to do that for Julia), and once it stabilizes, it can be included in Julia if necessary.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [February 10, 2026, 12:02pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/59 "2026-02-10T12:02:05Z")

</div>

> [@fonsp](#):
>
> In short, I find Julia an unstable and difficult platform to develop for. Precompilation is slow, developer tooling is lacking, and with every Julia release, I fear that my packages will stop working (they often do).

I would like to bring back the initial concerns raised by the OP. Most comments here are about breaking changes, but people forget how long pre-compilation and incomplete tooling are even more serious issues from the view point of a beginner.

The conversation around breaking changes and internal APIs is important, but IMHO it is very minor compared to the full programming experience with Julia. Students in other fields don’t even know what an API is. However, they **feel** the slowness when they hit Enter in a script or Pluto notebook. And when they get more experienced, they **feel** the pain of debugging something that is not working as expected.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 10, 2026, 12:21pm UTC](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497/60 "2026-02-10T12:21:09Z")

</div>

> [@juliohm](#):
>
> incomplete tooling

Can you, or the OP, please explain what specific tooling you are missing?

It would help focus the discussion.

[Previous page](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497.md?page=2)

[Next page](https://discourse.julialang.org/t/i-find-it-hard-to-develop-in-julia/135497.md?page=4)
