How does one initialize data into a module only once?

Based on your output, perhaps you are manipulating the LOAD_PATH? How are your files organized on disk and how are you getting them into Julia?

Let me try to recreate your situation. In a temporary folder I have created files A.jl, B.jl, C.jl, D.jl, and E.jl as follows:

$ find . -type f -print -exec cat {} \;
./A.jl
module A

const TestData = Dict()
function __init__()
    println("Running init")
    @assert isempty(TestData)
    TestData[1] = "1"
    if ccall(:jl_generating_output, Cint, ()) != 1
        println("We are actual loading the module for runtime, not caching code to disk. TestData keys: ", keys(TestData))
        TestData[2] = "2"
    else
        println("Hit the else. TestData keys: ", keys(TestData))
        TestData[3] = "3"
    end
end

end

./B.jl
module B
    using A
end

./C.jl
module C
    using A
end

./D.jl
module D
    using A
end

./E.jl
module E
    using A, B, C, D
end

In a Julia REPL, I then do the following.

$ julia --project=. --banner=no

julia> readdir()
5-element Vector{String}:
 "A.jl"
 "B.jl"
 "C.jl"
 "D.jl"
 "E.jl"

julia> push!(LOAD_PATH, pwd())
4-element Vector{String}:
 "@"
 "@v#.#"
 "@stdlib"
 "~/src/julia_module_test"

julia> using A
[ Info: Precompiling A [top-level]
Running init
We are actual loading the module for runtime, not caching code to disk. TestData keys: Any[1]

julia> using B
[ Info: Precompiling B [top-level]
Running init
Hit the else. TestData keys: Any[1]

julia> using C
[ Info: Precompiling C [top-level]
Running init
Hit the else. TestData keys: Any[1]

julia> using D
[ Info: Precompiling D [top-level]
Running init
Hit the else. TestData keys: Any[1]

julia> using E
[ Info: Precompiling E [top-level]
Running init
Hit the else. TestData keys: Any[1]

If I then run this again, I do not see the same output. A.__init__ only runs once.

$ julia --project=. --banner=no

julia> push!(LOAD_PATH, pwd())
4-element Vector{String}:
 "@"
 "@v#.#"
 "@stdlib"
 "~/src/julia_module_test"

julia> using A
Running init
We are actual loading the module for runtime, not caching code to disk. TestData keys: Any[1]

julia> using B

julia> using C

julia> using D

julia> using E

To recreate the initial situation, I need to remove the A.ji file in my $JULIA_DEPOT_PATH/compiled/v#.#, which defaults to ~/.julia/compiled/v1.7 since I am using Julia 1.7.

$ rm ~/.julia/compiled/v1.7/A.ji # modify to v1.8 if you are using v1.8

$ julia --project=. --banner=no
julia> push!(LOAD_PATH, pwd())
4-element Vector{String}:
 "@"
 "@v#.#"
 "@stdlib"
 "/home/mkitti/src/julia_module_test"

julia> using A
[ Info: Precompiling A [top-level]
Running init
We are actual loading the module for runtime, not caching code to disk. TestData keys: Any[1]

julia> using B
[ Info: Precompiling B [top-level]
Running init
Hit the else. TestData keys: Any[1]

julia> using C
[ Info: Precompiling C [top-level]
Running init
Hit the else. TestData keys: Any[1]

julia> using D
[ Info: Precompiling D [top-level]
Running init
Hit the else. TestData keys: Any[1]

julia> using E
[ Info: Precompiling E [top-level]
Running init
Hit the else. TestData keys: Any[1]