# \[ANN\] AppBundler.jl - Bundle Your Julia GUI Application

**URL:** <https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971>\
**Category:** Package Announcements\
**Tags:** announcement, gui\
**Created:** [November 30, 2023, 11:40pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971 "2023-11-30T23:40:50Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 17, 2025, 1:43pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/21 "2025-10-17T13:43:17Z")

</div>

> [@Janis\_Erdmanis](#):
>
> A huge culprit is that I were not able to find the entrypoint to launch the application.

See: [KiteSimulators.jl/bin/autopilot at main · aenarete/KiteSimulators.jl · GitHub](https://github.com/aenarete/KiteSimulators.jl/blob/main/bin/autopilot)  
This script starts the app autopilot.

Regarding this message:

```julia-auto
ERROR: LoadError: ArgumentError: No file exists at given path: /Users/jerdmanis/BtSync/Projects/KiteSimulators.jl/data/kite.obj

```

A folder “data” must exist with well-defined content. The function `init_project()` creates the data folder and copies the required data files. See: [KiteSimulators.jl/docs/PackageInstallation.md at main · aenarete/KiteSimulators.jl · GitHub](https://github.com/aenarete/KiteSimulators.jl/blob/main/docs/PackageInstallation.md)

Not sure which changes would be needed to achieve compatibility with your installer.

---

<div class="post-metadata">

**Author:** ![Rakesh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakesh/32/202257_2.png) [@Rakesh](https://discourse.julialang.org/u/Rakesh)\
**Post date:** [October 17, 2025, 3:46pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/22 "2025-10-17T15:46:05Z")

</div>

> [@Janis\_Erdmanis](#):
>
> I am attempting to package [ImageColorThresholderApp.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/ImageColorThresholderApp), which relies on Makie.

ImageColorThresholderApp.jl author here. I’m planning to update ImageColorThresholderApp.jl which hasn’t been touched in years, and I’m very much looking forward to integrating it with AppBundler.jl.

Thank you so much for creating and maintaining AppBundler.jl! It’s a truly invaluable tool for making Julia applications accessible to a wider audience.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 18, 2025, 8:30am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/23 "2025-10-18T08:30:10Z")

</div>

It appears that KiteViewers.jl picked up a `joinpath(pwd(), "data")` directory, which overrides the `data` directory inside the package. When I tried KiteViewers.jl outside the KiteSimulators.jl directory, precompilation succeeded. I then copied `kite.obj` from KiteViewers.jl into KiteSimulators.jl, which fixed this problem.

However, I encountered an error with `conda install -y pyqt` that did not work. Additionally, AppBundler.jl itself does not support bundling items produced by running `deps/build.jl`, so I will not proceed with KiteSimulators.jl this time.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 18, 2025, 9:35am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/24 "2025-10-18T09:35:59Z")

</div>

I made a simple entry point in the fork [GitHub - JanisErdmanis/ImageColorThresholderApp.jl: GUI tool for thresholding color images](https://github.com/JanisErdmanis/ImageColorThresholderApp.jl) that I built and tested locally with AppBundler. There is a minor issue with AppBundler.jl regarding its reliance on the `Manifest.toml` file, which I will fix later today with a patch version. Once that is done, I will open a PR.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 18, 2025, 10:01am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/25 "2025-10-18T10:01:54Z")

</div>

> [@Janis\_Erdmanis](#):
>
> Additionally, [AppBundler.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/AppBundler) itself does not support bundling items produced by running `deps/build.jl`

I am not aware of using `build.jl`. Where am I (or one of my dependencies) is using it?

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 18, 2025, 10:37am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/26 "2025-10-18T10:37:40Z")

</div>

The issue is reliance on PyPlot. It actually does not have `deps/build.jl` but instead instantiates the project at runtime through the ` __init__ ` block, which may actually work in this case. However, python dependencies would not be bundled 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 18, 2025, 11:39am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/27 "2025-10-18T11:39:59Z")

</div>

> [@Janis\_Erdmanis](#):
>
> The issue is reliance on PyPlot.

Would this issue be solved if I replace PyPlot with Makie?

---

<div class="post-metadata">

**Author:** ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)\
**Post date:** [October 18, 2025, 1:52pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/28 "2025-10-18T13:52:36Z")

</div>

I think so! we at least have a simple PackageCompiler relocatibality test these days!

---

<div class="post-metadata">

**Author:** ![GeorgeGkountouras](https://avatars.discourse-cdn.com/v4/letter/g/77aa72/32.png) [@GeorgeGkountouras](https://discourse.julialang.org/u/GeorgeGkountouras)\
**Post date:** [October 18, 2025, 2:07pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/29 "2025-10-18T14:07:09Z")

</div>

@Janis_Erdmanis Following our earlier private discussion, I would be interested in using AppBundler in conjunction with JuliaC to create Windows/Mac [shared libraries](https://discourse.julialang.org/t/creating-a-shared-library-with-juliac/126477) that can be loaded from a C binary.

These should respect each platform’s rules w.r.t. bundling, RPATHs and so on. I can provide a Mac signature to test codesigning.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 18, 2025, 3:30pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/30 "2025-10-18T15:30:24Z")

</div>

Yes. ImageColorThresholderApp.jl that depends on Makie compiles fine. If you can define `KiteSimulators.main` function so that the application can be started with:

```julia-auto
julia --project=. --eval "using KiteSimulators"

```

then bundling the application will be quite trivial by following the instructions in the anouncement.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 18, 2025, 4:01pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/31 "2025-10-18T16:01:32Z")

</div>

> [@Janis\_Erdmanis](#):
>
> then bundling the application will be quite trivial by following the instructions in the anouncement.

Not clear to me yet: I need a data directory that contains a number of input/ configuration files that the user should be able to modify. Should the `main()` function create that relative to the current directory and populate it?

Furthermore, how can a main() function automatically be executed just by doing `using MyPackage`?

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 18, 2025, 4:32pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/32 "2025-10-18T16:32:46Z")

</div>

The way to work on input is using a file dialog. NativeFileDialog.jl is perfect for that.

A simple approach is to open the file dialogue in the main function, where the user chooses a file or folder, and then launch the application window. Later, you can add the ability to change the file directories within the UI itself.

> [@ufechner7](#):
>
> Furthermore, how can a main() function automatically be executed just by doing `using MyPackage`?

This is the new feature of Julia 1.11 - [Command-line Interface · The Julia Language](https://docs.julialang.org/en/v1/manual/command-line-interface/#The-Main.main-entry-point) It is only executed in noninteractive mode automatically when the module is loaded in the main with `using MyPackage`.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 18, 2025, 6:10pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/33 "2025-10-18T18:10:01Z")

</div>

I encountered an issue preventing the precompilation of GLMakie.jl on headless Windows and MacOS runners. On Linux, I have a workaround, and both precompilation and the full bundle can be created.

It seems that one needs to build bundles locally on Windows and MacOS, which I tried to avoid.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [October 23, 2025, 3:29pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/34 "2025-10-23T15:29:11Z")

</div>

# AppBundler v0.4.7

[Documentation](https://github.com/PeaceFounder/AppBundler.jl) | [Examples](https://github.com/PeaceFounder/AppBundler.jl/tree/main/examples)

I have been actively testing the AppBundler across other repositories to uncover as many bugs as possible before I build on this foundation. I managed to make bundles for [ImageColorThresholderApp](https://github.com/rakeshksr/ImageColorThresholderApp.jl/pull/4) (except windows) and [KomaMRI](https://github.com/JuliaHealth/KomaMRI.jl/pull/640).

Currently, the following GUI frameworks have been tested with AppBundler across different platforms:

| Framework | Platform Support | Notes | Examples |
| --- | --- | --- | --- |
| QML | ✓ All platforms | Fully supported | [PeaceFounderClient](https://github.com/PeaceFounder/PeaceFounderClient/releases) |
| GLFW | ✓ All platforms | Fully supported | none |
| Gtk/Mousetrap | ⚠ macOS, Linux | Does not launch on Windows | none |
| Makie | ⚠ All platforms | [GLMakie may not work on Windows](https://github.com/MakieOrg/Makie.jl/issues/5342) | [ImageColorThresholderApp](https://github.com/rakeshksr/ImageColorThresholderApp.jl/pull/4) |
| Blink | ⚠ All platforms | Requires heavy patching for relocability | [KomaMRI](https://github.com/JuliaHealth/KomaMRI.jl/pull/640) |
| Electron | ✓ All platforms | Fully supported | [BonitoBook](https://github.com/SimonDanisch/BonitoBook.jl/pull/34) |

I would love to add more examples; however, very few Julia GUI applications document and make clear how to launch them. Ideally, everyone would define `(@main)(ARGS)`, introduced in Julia 1.11, which also enables distributing them as Pkg apps.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [November 13, 2025, 7:43pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/35 "2025-11-13T19:43:15Z")

</div>

# AppBundler v0.5.0

[Documentation](https://github.com/PeaceFounder/AppBundler.jl) | [Examples](https://github.com/PeaceFounder/AppBundler.jl/tree/main/examples)

AppBundler now makes it straightforward to create complete Julia distributions with packages pre-compiled and ready to use. This enables several use cases:

- **Educational environments** : Deploy Julia in computer labs without requiring students to wait through compilation of large packages like Makie or DifferentialEquations

- **Onboarding** : Provide newcomers with a distribution that includes popular ecosystem packages, creating a smoother first-time experience

- **Air-gapped deployments** : Create self-contained Julia distributions for offline or restricted network environments

Initial groundwork has been added for distributing command-line applications, with ongoing exploration of user-facing endpoint patterns. For a simple command-line application, DMG comes in at approximately 90 MB.

The next development phase will focus on integrating PackageCompiler and JuliaC to decrease application startup times and minimise installer sizes.

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [November 14, 2025, 2:37am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/36 "2025-11-14T02:37:03Z")

</div>

> [@Janis\_Erdmanis](#):
>
> **Air-gapped deployments** : Create self-contained Julia distributions for offline or restricted network environments

Very cool! How does this work with lazy artifacts?

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [November 14, 2025, 10:11am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/37 "2025-11-14T10:11:36Z")

</div>

Currently, it seems they are downloaded at runtime and placed in the user’s `DEPOT_PATH`. I overlooked them. There appears to be an easy fix by using `include_lazy=true` when retrieving them with [`Artefacts.select_downloadable_artifacts`](https://docs.julialang.org/en/v1/stdlib/Artifacts/#Artifacts.select_downloadable_artifacts), which I plan to implement.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [December 9, 2025, 3:32pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/38 "2025-12-09T15:32:24Z")

</div>

# AppBundler v0.6.0

[Documentation](https://github.com/PeaceFounder/AppBundler.jl) | [Examples](https://github.com/PeaceFounder/AppBundler.jl/tree/main/examples)

This release completes AppBundler’s core feature set by integrating system image generation and native compilation through JuliaC. The focus now shifts toward API refinement and documentation for the v1.0 release—feedback on naming and API design is welcome.

## System image generation

AppBundler now includes [SysImgTools](https://github.com/PeaceFounder/AppBundler.jl/blob/main/src/Utils/SysImgTools.jl), a module that handles system image creation in ~100 lines by building on `Base.Linking`. This eliminates the need for external compiler installation. To create a system image, specify which packages to bake in:

```julia
spec = JuliaAppBundle(project; sysimg_packages = ["QMLApp"])
dmg = DMG(project; windowed = true)
bundle(spec, dmg, joinpath(build_dir, "qmlapp.dmg"))

```

For project dependencies not included in `sysimg_packages`, precompilation cache is used instead. This enables hybrid approaches where critical packages use system images while others rely on pkgimages—useful for Julia distributions with GUI shells, significantly improving startup times.

## Selective assets

Applications can now include only specified assets, reducing distribution size:

```julia
asset_spec = Dict{Symbol, Vector{String}}(
    :QMLApp => ["src/App.qml"]
)

spec = JuliaAppBundle(project; sysimg_packages = ["QMLApp"], 
                      asset_rpath = "assets", asset_spec)

```

This creates an assets directory with declared files accessible via `pkgdir(@ __MODULE__ )`, while removing redundant source files. AppEnv launched via `startup.jl` handles this by reading a pkgorigins index at startup from `$(dirname(Sys.BINDIR))/index`, which maps packages to their asset locations, providing flexibility in where assets can be stored.

## JuliaC integration and AppEnv

Bundling with JuliaC compilation is now supported. AppEnv package handles platform-specific initialization through a config file at `$(dirname(Sys.BINDIR))/config`:

```julia
import AppEnv

function (@main)(ARGS)
    AppEnv.init()
    println(AppEnv.USER_DATA) # Sandbox-assigned user data directory
    println(pkgdir(@ __MODULE__ )) # Points to assets when compiled
end

```

To compile and bundle the application using JuliaC:

```julia
asset_spec = Dict{Symbol, Vector{String}}(
    :AppEnv => ["LICENSE"]
)

spec = JuliaCBundle(project; asset_spec, trim = true)
msix = MSIX(project; windowed = false)
bundle(spec, msix, joinpath(build_dir, "cmdapp.msix"))

```

During interactive development, `AppEnv.init()` is safely ignored. With trimming enabled, simple applications reach 20 MB (Snap) or 40 MB (MSIX). Compiled applications integrate with platform conventions—appearing as `cmdapp.exe` on Windows and `cmdapp` on Linux.

## Future work and v1.0

The project is feature-complete. Work now focuses on API polish, comprehensive documentation, and addressing community feedback. See [`test/release.jl`](https://github.com/PeaceFounder/AppBundler.jl/blob/main/test/release.jl) for complete examples until documentation is finalized.

---

<div class="post-metadata">

**Author:** ![KSepetanc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ksepetanc/32/10841_2.png) [@KSepetanc](https://discourse.julialang.org/u/KSepetanc)\
**Post date:** [December 9, 2025, 8:20pm UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/39 "2025-12-09T20:20:24Z")

</div>

Thank you for all your hard work and really quick development. It is much appreciated.

Here are some of my questions (technical details for v0.6).

From now Appbundler supports JuliaC compilation. As far I know JuliaC requires Julia 1.12. How does that reflect with open issue [#20](https://github.com/PeaceFounder/AppBundler.jl/issues/20) for support of 1.12? Does that issue no longer apply for the new Appbundler or 1.12 is still not fully supported?

Examples (such as `examples/QMLApp`) specify AppEnv using Sources section of `Project.toml`. Will that be updated or can that be avoided? Is AppEnv registered package / package extension?

How does `JuliaAppBundle` implementation (without JuliaC) compare to 0.5 implementation? Does it still copy basically full Julia into installation directory after app install?

Looking forward to documentation and future patches to try everything out.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [December 10, 2025, 11:04am UTC](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971/40 "2025-12-10T11:04:12Z")

</div>

Thank you for the kind words and for your detailed questions!

Regarding Julia 1.12 support and issue [#20](https://github.com/PeaceFounder/AppBundler.jl/issues/20): The issue still applies. JuliaC does require Julia 1.12, but there’s currently an OpenSSL executable availability problem. My workflow is: install JuliaC with Julia 1.12, then run AppBundler via Julia 1.11. This is why JuliaC isn’t yet in the CI pipeline—I have submitted two potential fixes: this [PR in Julia](https://github.com/JuliaLang/julia/pull/60176) and [OpenSSL\_CLI](https://github.com/JuliaPackaging/Yggdrasil/pull/12452). If neither resolves, I’ll investigate alternatives like vendoring Artifacts.toml and downloading OpenSSL manually via `build/deps.jl`.

AppEnv is a registered package that anyone can include in their projects. When using `JuliaAppBundle`, AppEnv is optional—it’s automatically incorporated during bundling and launched at `startup.jl`. However, it’s necessary for JuliaC-created bundles, which is why I registered it. It’s harmless during development: it checks for a config file and does nothing if absent, except setting `AppEnv.USER_DATA` to a temporactory (or respecting the `USER_DATA` environment variable if set).

Comparing JuliaAppBundle to v0.5: `JuliaAppBundle` extends the v0.5 implementation and still copies the full Julia installation directory. The key addition is that it can now override the system image. Testing shows it adds about 50MB in compressed form compared to `JuliaCBundle` (without trimming) but doesn’t affect launch performance. `JuliaAppBundle` is more suitable for creating various Julia distributions while also supporting app creation, whereas `JuliaCBundle` is exclusively for app deployment. `JuliaAppBundle` is particularly useful for debugging—you can launch the Julia REPL and investigate issues interactively, then switch to `JuliaCBundle` once everything works.

Looking forward to your feedback once you try it out!

[Previous page](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971.md?page=1)

[Next page](https://discourse.julialang.org/t/ann-appbundler-jl-bundle-your-julia-gui-application/106971.md?page=3)
