May 31, 2024
Summary How to create a GitHub Actions workflow to automatically build a Rust app. Create a GitHub release and attach the binary to it for all platforms. For example if you have a Rust CLI app that you want to publish the binaries to GitHub so people can download your tools, this is how to do it.
Overview
Prerequisites
GitHub Actions Workflow
name : Deploy # Name of the workflow
- "[0-9]+.[0-9]+.[0-9]+" # This will run the workflow on every tag that matches the regex
# The project name specified in your Cargo.toml
With this we will automatically trigger the workflow when we push a tag
with name like 1.0.0, 1.0.1, 1.1.2
etc. Replace the <REPLACE>
with the name of your project. You will find this in your cargo.toml
file under bin
, something like this:
name = "<YOUR_PROJECT_NAME>"
We now want to set up a job that will compile our Rust app.
We do this by utilizing a matrix strategy,
you can read more about this here:
https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs
# Set the job to run on the platform specified by the matrix below
runs-on : ${{ matrix.runner }}
# You can add more, for any target you'd like!
target : x86_64-unknown-linux-gnu
target : x86_64-pc-windows-msvc
target : x86_64-apple-darwin
target : aarch64-apple-darwin
uses : actions/checkout@v3
uses : dtolnay/rust-toolchain@stable
targets : "${{ matrix.target }}"
uses : Swatinem/rust-cache@v2
run : cargo build --verbose --locked --release --target ${{ matrix.target }}
We will now have the environment setup for each platform to be able to compile our Rust app.
Build and attach the Binary to the Release
Now we want to actually compile the binary and attach it to the release.
We can do this as follows:
run : cargo build --verbose --locked --release --target ${{ matrix.target }}
if [[ "${{ matrix.runner }}" == "windows-latest" ]]; then
# The built binary output location
BIN_OUTPUT="target/${{ matrix.target }}/release/${PROJECT_NAME}${BIN_SUFFIX}"
# Define a better name for the final binary
BIN_RELEASE="${PROJECT_NAME}${BIN_SUFFIX}"
BIN_RELEASE_VERSIONED="${PROJECT_NAME}-${{ github.ref_name }}-${{ matrix.name }}${BIN_SUFFIX}"
# Move the built binary where you want it
mv "${BIN_OUTPUT}" "./${BIN_RELEASE}"
if [ "${{ matrix.os }}" = "windows-latest" ]; then
7z a "./${BIN_RELEASE}-${{ matrix.name }}.zip" "./${BIN_RELEASE}"
echo "ASSET=./${BIN_RELEASE}-${{ matrix.name }}.zip" >> $GITHUB_ENV
tar -czf "./${BIN_RELEASE}-${{ matrix.name }}.tar.gz" "./${BIN_RELEASE}"
echo "ASSET=./${BIN_RELEASE}-${{ matrix.name }}.tar.gz" >> $GITHUB_ENV
Create a Release
The last step is to actually publish the release with the binary files attached.
uses : softprops/action-gh-release@v1
files : ${{ env.ASSET }} # Attach the binary to the release
Summary
Here is the workflow we created, you can also see how I use this in my Open Source DNS CLI tool, dns-cli
# The project name specified in your Cargo.toml
# Set the job to run on the platform specified by the matrix below
runs-on : ${{ matrix.runner }}
# You can add more, for any target you'd like!
target : x86_64-unknown-linux-gnu
target : x86_64-pc-windows-msvc
target : x86_64-apple-darwin
target : aarch64-apple-darwin
uses : actions/checkout@v3
uses : dtolnay/rust-toolchain@stable
targets : "${{ matrix.target }}"
uses : Swatinem/rust-cache@v2
run : cargo build --verbose --locked --release --target ${{ matrix.target }}
if [[ "${{ matrix.runner }}" == "windows-latest" ]]; then
# The built binary output location
BIN_OUTPUT="target/${{ matrix.target }}/release/${PROJECT_NAME}${BIN_SUFFIX}"
# Define a better name for the final binary
BIN_RELEASE="${PROJECT_NAME}${BIN_SUFFIX}"
BIN_RELEASE_VERSIONED="${PROJECT_NAME}-${{ github.ref_name }}-${{ matrix.name }}${BIN_SUFFIX}"
# Move the built binary where you want it
mv "${BIN_OUTPUT}" "./${BIN_RELEASE}"
if [ "${{ matrix.os }}" = "windows-latest" ]; then
7z a "./${BIN_RELEASE}-${{ matrix.name }}.zip" "./${BIN_RELEASE}"
echo "ASSET=./${BIN_RELEASE}-${{ matrix.name }}.zip" >> $GITHUB_ENV
tar -czf "./${BIN_RELEASE}-${{ matrix.name }}.tar.gz" "./${BIN_RELEASE}"
echo "ASSET=./${BIN_RELEASE}-${{ matrix.name }}.tar.gz" >> $GITHUB_ENV
uses : softprops/action-gh-release@v1