[ANN] AppBundler v1.0: Native Installers for Julia Applications

Packaging a Julia application into a native installer has traditionally meant wrestling with platform-specific tooling on each target system. I am pleased to announce AppBundler v1.0 changes that. Turn any Julia application into a Snap (Linux), MSIX (Windows), or DMG (macOS) installer without leaving the Julia ecosystem, using cross-compiled utilities from Yggdrasil instead.

For those following along from earlier announcements, this release marks the first stable version with a substantial API redesign.

Getting started

If you can launch your application with julia --project=. -m MyApp, it’s ready to bundle. Install AppBundler as an app with ]app add AppBundler, make sure ~/.julia/bin is in your PATH, then build:

appbundler build . --build-dir=build --selfsign

This creates a platform-local bundle in the build directory.

This makes it easy to distribute your Julia app to non-technical users via a self-contained installer, avoid setting up packaging tools on every platform, and maintain a simple CI workflow for cross-platform bundling (e.g. Jumbo CI).

Compilation options

Mode Best for Trade-off
None Fastest builds, cross-platform bundling Compilation on the user’s machine
Pkgimages Fast builds, fast startup Loading overhead, larger binaries
Sysimage Fastest startup Longer build time
JuliaC Smallest binaries, fastest startup Requires explicit asset declarations

Sysimage and pkgimage strategies can be combined for applications that load some packages on demand. In all cases, non-Julia assets referenced with pkgdir(@__MODULE__) remain accessible.

Configuration

The resulting bundle can be configured via command line, LocalPreferences.toml, or by overriding configuration file templates within the project’s meta directory. All major LocalPreferences.toml use cases have been manually tested across all three platforms.

See Jumbo, PeaceFounderClient, BonitoBook, and KomaMRI for real-world use cases, and start experimenting with the listed examples. For detailed configuration and deployment options, see the documentation.

What’s next

With v1.0 shipped, the project enters maintenance mode. A second phase of NLNET funding is lined up, which, if approved, would support further development. Near-term plans include trimming indirect dependencies to speed up installation. If funding comes through, priorities include making code signing robust for Apple notarization, integrating MSIX code signing with a hardware token, and adding Flatpak support. Bundling non-Julia projects (Rust, Go) via cross-compilation is another interesting direction. If any of this aligns with your needs, I’m open to consulting and collaboration — feel free to reach out.

36 Likes

Thanks for the good work!

Question: As far as I know, PyPlot.jl is not supported. Which plotting libraries work well with AppBundler? Does Makie work? My experience is that even Plots.jl often fails to plot when put into a system image because the display stack is frozen at compile time.

1 Like

Makie works just fine, which I had tested for bundling via ImageColorThresholderApp. I did hit an issue on Windows there, but it turned out to be a problem with my virtual machine setup that has issues with Makie itself. Pretty much every other plotting library should work out of the box except PyPlot.jl, as it depends on Python, which AppBundler does not bother bundling. For instance, bundling GR works just fine, which you can try with:

module SinPlotter

using GR

function (@main)(args)
    x = range(0, 2π, length=200) |> collect
    y = sin.(x)

    GR.plot(x, y,
        title = "Plot of sin(x)",
        xlabel = "x",
        ylabel = "y",
        linewidth = 2
    )

    println("Displaying plot. Press Enter to exit.")
    readline()

    return 0
end

export main

end # module SinPlotter

And build it the same way via appbundler build . --build-dir=build --selfsign.

2 Likes

Thanks for this, it really pushes the ecosystem forward!

Just confirming the status of a couple specific cases:

  1. A compiled CUDAApp would not download or compile on the user’s machine.
  2. Windows libraries made with JuliaC are still waiting for upstream support in JuliaC itself.

I would be very interested in this! I’ve had a lot of problems with snap on fedora so I have kind of given up on it. Could you estimate how much work it would be to add flatpak support? I might pick this up if you have no time

2 Likes

Same questions :wink: I don’t have a CUDA system, so I can’t test the built applications, but I do expect CUDA-enabled applications to run just fine as the relevant artefacts are bundled in. Regarding bundling libraries on Windows with MSIX, it may be possible using VFS — you would need to find the appropriate AppxManifest.xml configuration and bundle the libraries manually via the API (Reference · AppBundler.jl). This is a fairly sophisticated use case, so for more hands-on support I’m available for consulting to hammer out the details.

2 Likes

It’s a moderate level of work with some manual testing if one relies on flatpak-builder being installed on the host system. AppBundler so far distributes all tooling via Yggdrasil, and putting flatpak-builder there is a hard problem — it appears that flatpak-builder and the Flatpak runtime are interleaved, which couples it to the Linux kernel and makes the tooling very difficult to bundle independently.

That said, it seems feasible to build a Flatpak package using OSTree alone, which reduces the question to whether OSTree can be cross-compiled with a Yggdrasil recipe. I don’t have an answer to that yet, but it’s the first thing to figure out.

2 Likes

Thanks! Would be great to have this information in a github issue to track progress, if it isn’t already

Sure! Open an issue