End-to-end example of multi-platform build and publish (Go/Rust)?

I’m trying to understand the complete workflow for building and publishing packages that work on multiple platforms (e.g., both macOS and Linux).

I’ve read some documentation about how to set up multi-platform builds, but I’m looking for a concrete end-to-end example, ideally for:

  • Golang CLI application, or
  • Rust CLI application

Specifically, I’d like to see:

  1. How to structure the manifest.toml for multi-platform builds
  2. The actual build process on different platforms (do I need to build on each platform separately?)
  3. How to use flox publish after building to make the package installable on both Mac and Linux
  4. Whether there are any CI/CD examples or best practices for automating this

Is there a working example repository or guide that walks through this complete workflow? Even after reading the docs, I’d really benefit from seeing a real-world example of how this works in practice.

Thanks!

I’m looking to see if we have some examples to share, or further guidance, but I can provide a few answers in the meantime.

tldr: Use flox auth token to get a token to use in CI, and invoke FLOX_FLOXHUB_TOKEN=<token> flox publish -o <org> in CI on both mac and linux runners.

  1. Structuring the manifest.toml for multi-platform builds. There shouldn’t be much beyond any normal per system configuration for setting up the environment. By normal, I mean tailoring which packages or versions of packages per system. The build and publish operations happen in the context of the host system. If you can flox build your app, and run it via the ./results-* directory you should be good to go for publishing.
  2. Following on the previous, yes currently that’s the best way. We use both mac and linux github runners to invoke the publish operation.
  3. You just need to run the flox publish command on each system type. You can verify by looking at the package in Floxhub, or flox show <org>/<pkg> will also show which systems it’s available for.
  4. We have some build examples in different languages here. I’m looking to see what else I can dig up or setup.

I’ll add that we are working on solutions for access tokens to use for CI outside of “your” token which is what flox auth token gives you currently. It’s not the best but it’ll get you running for a PoC. If you omit the -o <org> it’ll publish to your personal namespace.

We also have lots in the works for the Build/Publish/Consume pipeline to streamline this.

Following on some of @billlevine’s suggestions:

The flox-build-examples repo he linked is a good resource to see how builds can be executed for various ecosystems, including Go and Rust.

In the Go example, we included three different variations on how to execute a build:

  • quotes-app-go is an example of the default way to execute a manifest build
  • quotes-app-go-pure is an example of how to build a Go application with the sandbox enabled (details) – the difference between this and the default build is that the application itself is built without network access, so the quotes-app-go-deps build is needed first to fetch and provide Go dependencies to the pure build in addition to those provided from the Flox environment
  • quotes-app-go-nix is an example doing the same as the pure build, but using a Nix expression

Note that each of these examples describe a complete build on their own; any of the three methods are suitable for doing multi-platform builds.

Like @billlevine mentioned, the process for building on multiple platforms currently is to execute flox build on each one. Internally, we do this with GitHub Actions similar to:

  build:
    name: "Build"

    strategy:
      matrix:
        os:
          - "ubuntu-22.04"
          - "ubuntu-22.04-arm"
          - "macos-latest"

    runs-on: "${{ matrix.os }}"

    if: ${{ github.event_name != 'push' }}

    steps:
      - name: "Checkout"
        uses: "actions/checkout@v4"
        with:
          fetch-depth: 0
          ref: "${{ github.head_ref }}"

      - name: "Install flox"
        uses: "flox/install-flox-action@main"

      - name: "Build"
        run: "flox build quotes-app-go"

Likewise, publishing can be done similarly:

  publish:
    name: "Publish"

    strategy:
      matrix:
        os:
          - "ubuntu-22.04"
          - "ubuntu-22.04-arm"
          - "macos-latest"

    runs-on: "${{ matrix.os }}"

    if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}

    steps:
      - name: "Checkout"
        uses: "actions/checkout@v4"
        with:
          fetch-depth: 0
          ref: "${{ github.head_ref }}"

      - name: "Install flox"
        uses: "flox/install-flox-action@main"

      - name: "Build & Publish"
        run: "flox publish quotes-app-go"

as @billlevine mentioned, you’ll need to have a FloxHub token available for this job for it to be able to publish.

Today, you can run flox auth token from the CLI to get a token. When using GitHub actions, we take that token and set it as a repository secret called FLOX_FLOXHUB_TOKEN which is automatically available to the job. In general, you’ll just need to make sure the token is available in the FLOX_FLOXHUB_TOKEN environment variable when flox publish is run.

One last note is that flox publish implicitly executes flox build first – to that end, we typically do flox build in PRs for testing, but only need to run flox publish on merges or release events as it always builds before executing the publish operation.

Hope this helps some – please let us know if you need additional detail or clarification.