# \[ANN\] Revise.jl v3.13: Struct revision support

**URL:** https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818
**Category:** Tooling
**Tags:** revise
**Created:** [December 31, 2025, 6:00pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818 "2025-12-31T18:00:16Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![aviatesk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aviatesk/32/7610_2.png) [@aviatesk](https://discourse.julialang.org/u/aviatesk)
#### Post date: [December 31, 2025, 6:00pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/1 "2025-12-31T18:00:17Z")

</div>

Happy New Year, everyone!🎉🎍

A new year’s gift for you all: [Revise.jl v3.13](https://github.com/timholy/Revise.jl/blob/master/NEWS.md#revise-313) with **struct revision support**.  
Here’s what’s new in this release.

## Struct Revision (Julia 1.12+)

Revise can now handle changes to struct definitions! When you modify a struct, Revise automatically re-evaluates the struct definition along with any methods or types that depend on it.

For example, if you have:

```julia
struct Inner
    value::Int
end

struct Outer
    inner::Inner
end

print_value(o::Outer) = println(o.inner.value)

```

And change `Inner` to:

```julia
struct Inner
    value::Float64
    name::String
end

```

Revise will redefine `Inner`, and also re-evaluate `Outer` (which uses `Inner` as a field type) and `print_value` (which references `Outer` in its signature).

See [PR #894](https://github.com/timholy/Revise.jl/pull/894) for implementation details.

### Limitations: Binding revision is not yet supported

While struct revision is supported, more general “binding revision” is not yet implemented. Specifically, Revise does not track implicit dependencies between top-level bindings.

For example:

```julia
MyVecType{T} = Vector{T} # changing this to AbstractVector{T} won't update MyVec
struct MyVec{T}
    v::MyVecType{T}
end

```

If you change `MyVecType{T}` from `Vector{T}` to `AbstractVector{T}`, the struct `MyVec` will **not** be automatically re-evaluated because Revise does not track the dependency edge from `MyVecType` to `MyVec`. The same applies to `const` bindings and other global bindings that are referenced in type definitions.

This limitation actually also affects macros and generated functions—if you change a macro definition, the changes won’t propagate to code that has already expanded that macro.

**Workaround** : You can manually call `revise(MyModule)` to force re-evaluation of all definitions in `MyModule`, which will pick up the new bindings.

Supporting general binding revision would require tracking implicit binding edges across all top-level code, which involves significant interpreter enhancements. This is deferred to future work.

* * *

## Other Changes

### Added

- `Revise.dont_watch(pkg)` and `Revise.allow_watch(pkg)` functions with [Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl) persistence. Direct modification of `dont_watch_pkgs` set is deprecated and will be removed in a future major version. ([#976](https://github.com/timholy/Revise.jl/pull/976))

### Changed

- `Revise.silence()` now uses [Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl) for persistent storage instead of file-based persistence. ([#976](https://github.com/timholy/Revise.jl/pull/976))
- Removed unused `Requires` and `Unicode` dependencies. ([#977](https://github.com/timholy/Revise.jl/pull/977))
- Internal code quality improvements ([#979](https://github.com/timholy/Revise.jl/pull/979), [#980](https://github.com/timholy/Revise.jl/pull/980), [#981](https://github.com/timholy/Revise.jl/pull/981), [#982](https://github.com/timholy/Revise.jl/pull/982))

### Fixed

- Fixed test failures related to non-normalized base paths. ([#974](https://github.com/timholy/Revise.jl/pull/974), xref: [JuliaLang/julia#60251](https://github.com/JuliaLang/julia/pull/60251))
- Fixed precompilation warning. ([#984](https://github.com/timholy/Revise.jl/pull/984), closes [#956](https://github.com/timholy/Revise.jl/issues/956) and [#969](https://github.com/timholy/Revise.jl/issues/969))

* * *

For more details, see the [documentation](https://timholy.github.io/Revise.jl/stable/).

---

<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: [January 1, 2026, 10:59am UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/2 "2026-01-01T10:59:03Z")

</div>

A big thank you to everyone who contributed to this! I know it was a major effort that involved a lot of work on the internals of Julia.

❤

(From the person who opened [the original issue in 2017](https://github.com/timholy/Revise.jl/issues/18) 😉)

---

<div class="post-metadata">

### Author: ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)
#### Post date: [January 5, 2026, 2:46pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/3 "2026-01-05T14:46:53Z")

</div>

> [@aviatesk](#):
>
> Revise will redefine `Inner`, and also re-evaluate `Outer`

This sounds great! But how to make use of it? On a new REPL after upgrading to Revise.jl v3.13.0 I get

```julia
julia> using Revise

julia> struct Inner
           value::Int
       end

julia> struct Outer
           inner::Inner
       end

julia> Outer |> sizeof
8

julia> Base.get_world_counter() |> Int
38691

julia> struct Inner
           value::Float64
           name::String
       end

julia> Outer |> sizeof
8

julia> using About

julia> Outer |> about
Concrete DataType defined in Main, 8B
  Outer <: Any

Struct with 1 fields:
• inner @world(Inner, 38685:38691)

 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                                   8B

(@v1.12) pkg> status Revise
Status `~/.julia/environments/v1.12/Project.toml`
  [295af30f] Revise v3.13.0

```

i.e. 8 byte where I would have expected 16 bytes.

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [January 5, 2026, 3:36pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/4 "2026-01-05T15:36:30Z")

</div>

Note that you’re not actually using Revise there. This behavior is base Julia’s and is discussed in [Inconsistencies in the meaning of code, post binding-partitioning · JuliaLang/julia · Discussion #58337 · GitHub](https://github.com/JuliaLang/julia/discussions/58337).

You can see that — without a subsequent redefinition of `Outer` itself — the struct still references the old `Inner`:

```julia-auto
julia> struct Inner
           value::Int
       end

julia> struct Outer
           inner::Inner
       end

julia> dump(Outer)
struct Outer <: Any
  inner::Inner

julia> struct Inner
           value::Float64
           name::String
       end

julia> dump(Outer)
struct Outer <: Any
  inner::@world(Inner, 38662:38668)

```

This is the reason d’être for using Revise.jl. If this is in a tracked file, then it’s Revise that finds that connection and automatically updates it:

```julia-auto
julia> using Revise

julia> write("code.jl", """
       struct Inner
           value::Int
       end
       struct Outer
           inner::Inner
       end
       """)

julia> includet("code.jl")

julia> sizeof(Outer)
8

julia> ### Now edit code.jl to use the new Inner definition...

julia> sizeof(Outer)
16

```

---

<div class="post-metadata">

### Author: ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)
#### Post date: [January 5, 2026, 3:59pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/5 "2026-01-05T15:59:41Z")

</div>

> [@mbauman](#):
>
> Note that you’re not actually using Revise there. This behavior is base Julia’s and is discussed in [Inconsistencies in the meaning of code, post binding-partitioning · JuliaLang/julia · Discussion #58337 · GitHub](https://github.com/JuliaLang/julia/discussions/58337).

Thanks! Your post and the linked discussion are both very informative. So in the end it’s a mix of two design decisions I was not aware of:

- The different handling of “method bodies” versus “type bodies” regarding binding-partitioning
- Revise.jl not tracking `Main`

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [January 6, 2026, 11:17pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/6 "2026-01-06T23:17:51Z")

</div>

> [@PatrickHaecker](#):
>
> [Revise.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/Revise) not tracking `Main`

Again, it’s not that revise was neglecting something, its that you weren’t using or interacting with Revise at all. Revise.jl has never watched your REPL and re-evaluated code based on things you did in your REPL. Revise doesnt truly watch modules, it’s all just about watching and analyzing files

---

<div class="post-metadata">

### Author: ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)
#### Post date: [March 17, 2026, 1:09pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/7 "2026-03-17T13:09:56Z")

</div>

A quick note on struct revision support: I and many other found that with large environments with many packages loaded, struct revision was far too slow to be useful. I managed to improve performance by [roughly a factor of 15](https://github.com/timholy/Revise.jl/pull/1013), but in my estimation it is still too slow to be turned on by default. I believe that future improvements in Julia itself might make it viable, but those will take a little longer to land.

Thus, in the shortly-to-appear 3.14 release, struct revision will be opt-in. There are instructions for setting this up at [Configuration · Revise.jl](https://timholy.github.io/Revise.jl/dev/config/#Enabling-struct-revision)

---

<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: [March 17, 2026, 1:42pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/8 "2026-03-17T13:42:40Z")

</div>

Just for clarification, is the configuration about the propagating re-evaluations (`Outer`, `print_value` in the example) after redefining the struct (`Inner`) or about all of it? From the linked configuration instructions saying the slowdown is caused by Revise scanning types and the method table, I’d assume that the struct redefinition would still occur because it doesn’t need to be traced to other expressions and Julia supports that without Revise. The wording however implies otherwise, and if that’s the case, could Revise eventually do it just to save the copy-paste into a REPL? `revise(mod)` is still an option but would reevaluate everything in a module, which is not always desired immediately after a struct redefinition.

---

<div class="post-metadata">

### Author: ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)
#### Post date: [March 17, 2026, 2:01pm UTC](https://discourse.julialang.org/t/ann-revise-jl-v3-13-struct-revision-support/134818/9 "2026-03-17T14:01:29Z")

</div>

Yes, as you say the need for the scan is find types like `Outer` than are defined in terms of a structure like `Inner` that is being redefined. Effectively Revise has to iterate over `subtypes(Any)` to find these. Currently that is too slow to be turned on by default.

Future changes to Julia might enable that search to be limited to types that were defined since the last scan occurred, but currently that’s WIP and of course speculative.
