# How to set up a monorepo with multiple Julia packages and GitHub Actions?

**URL:** <https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044>\
**Category:** Package Management\
**Created:** [October 10, 2025, 12:00pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044 "2025-10-10T12:00:12Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [October 10, 2025, 12:00pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/1 "2025-10-10T12:00:12Z")

</div>

Hey everyone,

I could use some guidance from folks who’ve gone through this before. I’ve been developing locally with a setup that has about ten Julia modules in a single repo. Each module is in its own sub-directory with its own src/, test/, and docs/ folder. Right now I just use plain include() and using across modules — no formal Project.toml or package registration yet.

Here’s roughly what it looks like:

MyApp/  
├── Module A/  
│ ├── src/  
│ ├── test/  
│ └── docs/  
├── Module B/  
│ ├── src/  
│ ├── test/  
│ └── docs/  
…

Each module is cleanly separated, and everything runs fine locally when I use relative paths and using. Now I’m getting ready to move this to GitHub and want to do it right — with proper Project.toml files, CI/CD testing, and documentation builds (Docs.jl, GitHub Actions, etc.).

What I’m trying to do

- Keep a monorepo, not split into ten separate repos.

- Make each module a package with its own Project.toml so I can using Module A etc.

- Have GitHub Actions “just work” for testing and docs for all modules.

- Avoid mistakes or rework others may have already gone through setting up monorepo workflows.

My questions

- What’s the best way to structure this monorepo so that CI/CD (GitHub Actions, coverage, docs) works cleanly for all sub-packages? Should I have one top-level Project.toml that references the sub-packages, or should everything be independent?

- How do people typically handle cross-module dependencies inside a monorepo (e.g., Module A depending on Module) — through dev paths or local registries? (not all modules are dependent upon each other, but some are at higher levels)

- Any examples of monorepos in the Julia ecosystem that follow this pattern (or close to it)?

I’ve seen plenty of examples of single-package setups, watched videos on Projects and Packages, but not many covering multi-package “app” style projects like this. I’ve had my head down developing, but need to plan for this migration now. I’m certain others have done this though, so I would love to hear from anyone who’s already worked through the packaging + CI details for something similar or if I have missed existing threads or docs that address this.

Thanks in advance — I’d really like to get this right before I migrate everything to GitHub!

— Steve

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [October 12, 2025, 12:42pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/2 "2025-10-12T12:42:30Z")

</div>

I think monorepos are possible since v1.11.  
You should have a Project.toml for each submodule and an additional top-level one.  
Since 1.11, a Project.toml has the “Sources” section ([11. Project.toml and Manifest.toml · Pkg.jl](https://pkgdocs.julialang.org/v1.12/toml-files/#The-%5Bsources%5D-section)), so that you can add unregistered dependencies in a portable way.

I’ve never tried a monorepo approach, but it seems that `Documenter.makedocs` ([Public API · Documenter.jl](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs)) has the capability you need.

For testing, it should be simply `using Pkg; Pkg.test("ModuleA"); Pkg.test("ModuleB"); ... Pkg.test()` from within `MyApp` environment. That will run `test/runtests.jl` files for the submodules ([13. API Reference · Pkg.jl](https://pkgdocs.julialang.org/v1/api/#Pkg.test)).

---

<div class="post-metadata">

**Author:** ![RomeoV](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/romeov/32/37687_2.png) [@RomeoV](https://discourse.julialang.org/u/RomeoV)\
**Post date:** [October 13, 2025, 5:20am UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/3 "2025-10-13T05:20:39Z")

</div>

Also check out the new `workspace` feature introduced in 1.12 that simplifies this a lot. This may remove any need for specifying sources in the first place.

---

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [October 13, 2025, 2:16pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/4 "2025-10-13T14:16:22Z")

</div>

@Vasily_Pisarev and @RomeoV Thanks for the insights. Super helpful. And, the new workspace features seems built-in for this as of just last week. Perfect timing! From the docs

"A workspace is defined in the base project by giving a list of the projects in it …This structure is particularly beneficial for developers using a monorepo approach, where a large number of unregistered packages may be involved. It is also useful for adding documentation or benchmarks to a package by including additional dependencies beyond those of the package itself. "

I am trying to finish up a new feature in the next few days and then I will give this a try and create a public repo example that uses these approaches to share back.

---

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [October 13, 2025, 8:28pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/5 "2025-10-13T20:28:02Z")

</div>

Some example monorepos are:

[https://github.com/MakieOrg/Makie.jl](https://github.com/MakieOrg/Makie.jl)  
and [https://github.com/JuliaIO/ChunkCodecs.jl](https://github.com/JuliaIO/ChunkCodecs.jl)

ChunkCodecs.jl is using `workspace`, and right now Makie.jl is using `sources`.

One big decision is whether you want all the packages in the monorepo to be updated in lockstep or if each can have completely independent versions. In ChunkCodecs.jl each package has independent versions and independent changelogs, and only uses the public stable API of the other packages.  
From what I can Makie.jl has more tight control of relative versions [Makie.jl/CairoMakie/Project.toml at 10d65fd67bb269ea96c6748d754fd3544bb3051c · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/blob/10d65fd67bb269ea96c6748d754fd3544bb3051c/CairoMakie/Project.toml#L27)

Also, most of the GitHub tools don’t work well with monorepos out of the box. For example, I never got tagbot or code coverage checks working in ChunkCodecs.jl, and currently do those manually.

---

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [October 18, 2025, 3:34pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/6 "2025-10-18T15:34:21Z")

</div>

It took me longer than planned to finish the dev task I was doing. But, it’s done. I’ll start this experiment tomorrow and put any progress here. Thanks again for pointers to help me get off on the right track.

---

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [October 19, 2025, 7:40pm UTC](https://discourse.julialang.org/t/how-to-set-up-a-monorepo-with-multiple-julia-packages-and-github-actions/133044/7 "2025-10-19T19:40:52Z")

</div>

I have started a toy repo as an experiment. I am not using workspaces yet (because it will be a while until that is in most people’s workflow, I’ll add that soon though).

> **[GitHub - stevenhughes73/JuliaMonoRepoApp: An example Julia mono repo. An App...](https://github.com/stevenhughes73/JuliaMonoRepoApp/tree/main)**
>
> main

TheForce is a base module that “runs through all things”. TheEmpire, and TheResistance use TheForce. The StarWarsApp uses everything.

```julia
using Pkg
Pkg.activate(".")
using TheResistance

```

loads TheResistance and all deps for TheResistance. The same for using on any other module or the whole app.

Github CI/CD is working for build and test. Not for docs yet. I am working on a doc that will go in StarWarsApp/docs to explain how I set this up based on guidance here, some videos, and Claude Sonnet 4.

I’ll work on docs CI/CD next.
