# How to organize modules in a composable way?

**URL:** <https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536>\
**Category:** General Usage\
**Tags:** modules, code-organization\
**Created:** [December 13, 2025, 7:14pm UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536 "2025-12-13T19:14:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mj2984](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mj2984/32/43833_2.png) [@mj2984](https://discourse.julialang.org/u/mj2984)\
**Post date:** [December 13, 2025, 7:14pm UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/1 "2025-12-13T19:14:58Z")

</div>

Suppose I have a module module\_init that defines a type init\_struct, and I am now trying to make multiple modules in different projects that build on top of this init\_struct. For example

./project\_init/src/module\_init.jl contains

```julia-auto
module module_init
export init_struct,do_something
struct init_struct end
function do_something(init_struct)
     #do something
end
end

```

Then I have a few projects: eg project\_sub1 and project\_sub2 that have their code like.

./project\_sub1/src/sub1\_module.jl contains

```julia-auto
module module_sub1
export sub1Struct,performSub1Action
include(raw"./project_init/src/module_init.jl")
using .module_init
struct sub1Struct{T}
     init::init_struct
     sub1::T
end
functon performSub1Action(input::sub1Struct{T}) where {T}
     do_something(input.init)
     # Do other actions for sub1
end
end

```

./project\_sub2/src/sub2\_module.jl contains

```julia-auto
module module_sub2
export sub2Struct,performSub2Action
include(raw"./project_init/src/module_init.jl")
using .module_init
struct sub2Struct{T}
     init::init_struct
     sub2::T
end
functon performSub2Action(input::sub1Struct{T}) where {T}
     do_something(input.init)
     # Do other actions for sub1
end
end

```

This is not ideal because the composability is gone. I cannot do something like

```julia-auto
include(“./project_init/src/module_init.jl”)
using .module_init
include("./project_sub1/src/sub1_module.jl")
using .module_sub1
init = init_struct()
sub1 = 3
data = sub1Struct(init,sub1)

```

Since the init\_struct inside the sub1 module has a different namespace module\_sub1.module\_init

I can try to import and re-export, but then I will not be able to easily use module\_sub1 and module\_sub2 simultaneously.

How should I organize my code such that I am able to do something like

```julia-auto
using .module_init
using .module_sub1
using .module_sub2

init = init_struct()
sub1 = 3
sub2 = 4
data1 = sub1Struct(init,sub1)
data2 = sub1Struct(init,sub2)

```

Similar to how I can use packages that is able to do this? Where I can do something like using module\_init on both module module\_sub1 and module\_sub1.

Is packages the only way to do this? Also, what is the difference between a package and a module. I am unable to find the right keywords to search for documentation in this area.

---

<div class="post-metadata">

**Author:** ![brianguenter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brianguenter/32/29519_2.png) [@brianguenter](https://discourse.julialang.org/u/brianguenter)\
**Post date:** [December 13, 2025, 8:44pm UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/3 "2025-12-13T20:44:55Z")

</div>

My first suggestion would be to refactor your code so you don’t need so many modules. My experience has been that submodules add significant complexity and cognitive overhead so I use them only for large projects where namespace collision is hard to avoid otherwise.

If refactoring is not possible then here is one way to accomplish what you want. Create three subprojects of your Main project, one for each module. Place the module code in those subproject directories. Then load the subproject packages with using rather than include.

Here’s how to create the subprojects starting from scratch. Enter the julia package manager by typing ] and then create the Main project directory:

```julia
@v1.12) pkg> generate Main
  Generating project Main:
    Main\Project.toml
    Main\src\Main.jl

```

Activate the Main project:

```julia
(@v1.12) pkg> activate Main
  Activating project at `C:\Users\seatt\OneDrive\Documents\temp\Main`

```

Now create the three subprojects that will contain the three modules:

```julia
(Main) pkg> generate Main\module_init
  Generating project module_init:
    Main\module_init\Project.toml
    Main\module_init\src\module_init.jl

(Main) pkg> generate Main\sub1Struct
  Generating project sub1Struct:
    Main\sub1Struct\Project.toml
    Main\sub1Struct\src\sub1Struct.jl

(Main) pkg> generate Main\sub2Struct
  Generating project sub2Struct:
    sub2Struct\Project.toml
    sub2Struct\src\sub2Struct.jl

```

Now link these subprojects as dependencies of the Main project:

```julia
(Main) pkg> dev Main\sub1Struct\\
   Resolving package versions...
    Updating `C:\Users\seatt\OneDrive\Documents\temp\Main\Project.toml`
  [95151458] + sub1Struct v0.1.0 `sub1Struct`
    Updating `C:\Users\seatt\OneDrive\Documents\temp\Main\Manifest.toml`
  [95151458] + sub1Struct v0.1.0 `sub1Struct`

(Main) pkg> dev Main\sub2struct\\
   Resolving package versions...
    Updating `C:\Users\seatt\OneDrive\Documents\temp\Main\Project.toml`
  [eadf8c1f] + sub2struct v0.1.0 `sub2struct`
    Updating `C:\Users\seatt\OneDrive\Documents\temp\Main\Manifest.toml`
  [eadf8c1f] + sub2struct v0.1.0 `sub2struct`

(Main) pkg> dev Main\module_init\\
   Resolving package versions...
    Updating `C:\Users\seatt\OneDrive\Documents\temp\Main\Project.toml`
  [c9778ed0] + module_init v0.1.0 `module_init`
    Updating `C:\Users\seatt\OneDrive\Documents\temp\Main\Manifest.toml`
  [c9778ed0] + module_init v0.1.0 `module_init`

```

Now check that everything is correct:

```julia
(Main) pkg> st
Project Main v0.1.0
Status `C:\Users\seatt\OneDrive\Documents\temp\Main\Project.toml`
  [c9778ed0] module_init v0.1.0 `module_init`
  [95151458] sub1Struct v0.1.0 `sub1Struct`
  [eadf8c1f] sub2struct v0.1.0 `sub2struct`

```

Now you can create julia code in the Main project directory like this:

```julia
using module_init
using module_sub1
using module_sub2

```

and your subpackages will be loaded correctly.

---

<div class="post-metadata">

**Author:** ![brianguenter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brianguenter/32/29519_2.png) [@brianguenter](https://discourse.julialang.org/u/brianguenter)\
**Post date:** [December 13, 2025, 8:45pm UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/4 "2025-12-13T20:45:38Z")

</div>

This is a good explanation of the difference between modules and packages [https://stackoverflow.com/questions/75511154/whats-the-difference-between-modules-and-packages-in-julia](https://stackoverflow.com/questions/75511154/whats-the-difference-between-modules-and-packages-in-julia)

---

<div class="post-metadata">

**Author:** ![mj2984](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mj2984/32/43833_2.png) [@mj2984](https://discourse.julialang.org/u/mj2984)\
**Post date:** [December 13, 2025, 9:03pm UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/5 "2025-12-13T21:03:04Z")

</div>

Thank you for the detailed explanation. If I consider the following case, say with a package like StaticArrays, I am able to do something like

```julia-auto
using Pkg
Pkg.add("StaticArrays")

```

then I can do DependentModule1.jl

```julia-auto
module DependentModule1
using StaticArrays
export StructType1
struct StructType1{T}
    field::SVector{3,T}
    enumeration::Int64
end
end

```

Similarly DependentModule2.jl

```julia-auto
module DependentModule2
using StaticArrays
export StructType2
struct StructType2{T}
    field::SVector{4,T}
    enumeration::Int64
end
end

```

And now it is possible to do this in the repl

```julia-auto
using StaticArrays
include("DependentModule1.jl")
include("DependentModule2.jl")
using .DependentModule1
using .DependentModule2

fieldStruct1 = SVector{3,Int64}((1,3,5))
fieldStruct2 = SVector{4,Int64}((0,2,4,6))
Struct1 = StructType1(fieldStruct1,0)
Struct2 = StructType2(fieldStruct2,1)

```

What is it about using Pkg that enables bypassing include(\<\<Path\_to\_StaticArrays.jl\>\>) and ability to remove the dot before using (using StaticArrays instead of using .StaticArrays)?

For the use case mentioned, module\_init is expected to be something equivalent to StaticArrays but something that should stay internal/local to the computers we are using.

Is the typical working environment, just a big Project like the one in your comment? If so, when does the equivalent of include(“StaticArrays.jl”) happen. Does it happen the moment we install a package, or is it during the first invokation of using StaticArrays in the code either in a module or in the script. If using StaticArrays occurs multiple times in a code (in the module it calls and in the code), is the equivalent of include(“StaticArrays.jl”) done once or multiple times (mulitple times should cause errors since it keeps replacing the references right)? Does the Project use a completely different mechanism to load the code of the invoked packages.

---

<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:** [December 13, 2025, 9:55pm UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/6 "2025-12-13T21:55:43Z")

</div>

> [@mj2984](#):
>
> What is it about using Pkg that enables bypassing include(\<\<Path\_to\_StaticArrays.jl\>\>) and ability to remove the dot before using (using StaticArrays instead of using .StaticArrays)?

You’re not supposed to `include` before each import in the first place, that’s why they’re separate actions. `include` evaluates a file’s text as Julia code into its parent module, while imports share names among existing modules. In your original example, `module_sub1` and `module_sub2` evaluated their own `module_init` expressions, in other words `module_sub1.module_init` and `module_sub2.module_init` are completely unrelated. Stripping the code down to just the module structure, you intended to do this instead:

```julia-auto
# some master file

module module_init # your include call could do this
end

module module_sub1
  using ..module_init # dots indicate how many levels up to find the imported module
end

module module_sub2
  using ..module_init
end

println(module_sub1.module_init === module_sub2.module_init) # true

```

The package approach lets an environment track the modules, so no need for dotted names or evaluations to a master file. Personally I think it’s overkill for such little code, as is making those two modules separate to begin with. You’d know better how your code should be organized, though, this is clearly a minimal example.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [December 14, 2025, 1:21am UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/7 "2025-12-14T01:21:25Z")

</div>

> [@mj2984](#):
>
> Is packages the only way to do this?

Yeah, use packages instead of abusing `include`.

> [@mj2984](#):
>
> what is the difference between a package and a module.

A module is just a namespace. That’s it. A package is a module with a project, to track dependencies.

---

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [December 16, 2025, 7:46am UTC](https://discourse.julialang.org/t/how-to-organize-modules-in-a-composable-way/134536/8 "2025-12-16T07:46:04Z")

</div>

There’s nothing wrong with `include()` plus `using .`.

But you should include all modules from the main project and replace `using .module_init` inside the submodules by `using ..module_init`, which tells `using` to look for the module in the parent module. Grandparents receive another dot for each generation.
