CI/CD for Rust Projects: GitHub Actions from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why CI/CD is Critically Important for Rust Projects



Rust is a systems programming language renowned for its performance and memory safety. However, even the most reliable code requires constant verification. Manual testing and building consume time and are prone to errors. CI/CD (Continuous Integration/Continuous Deployment) automates these processes, ensuring that every code change is checked by the compiler, tests, and linters before it reaches the main branch.



GitHub Actions is a built-in platform for automating workflows in GitHub. It is ideal for Rust projects due to its flexibility, free minute limit for public repositories, and a vast ecosystem of ready-made actions. In this article, we will cover the complete cycle of setting up CI/CD for Rust: from basic build to optimization using caching and deployment.



1. Basics: First Workflow for Building and Testing



Let's start by creating a minimal workflow. In the root of your repository, create a folder .github/workflows and a file ci.yml.



Basic ci.yml file



name: Rust CI

on: push: branches: [ "main" ] pull_request: branches: [ "main" ]

env: CARGO_TERM_COLOR: always

jobs: build: runs-on: ubuntu-latest

steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose


Breakdown of key elements:

  • on: Triggers — runs on push to main and on Pull Request creation.
  • env: The CARGO_TERM_COLOR variable enables colored log output.
  • actions/checkout: Standard action for cloning the repository.
  • dtolnay/rust-toolchain: The most popular action for installing Rust. Use stable, nightly, or a specific version.


This workflow is already useful: it guarantees that the code compiles and all tests pass. However, this is not enough for a real project.



2. Optimization: Dependency Caching and Multi-Platform Build



Each CI run downloads all dependencies from scratch. For Rust projects with many crates, this can take minutes. The solution is caching the ~/.cargo and target folders.



Adding Caching



jobs:  build:    runs-on: ubuntu-latest    steps:    - uses: actions/checkout@v4    - name: Install Rust      uses: dtolnay/rust-toolchain@stable    - name: Cache dependencies      uses: actions/cache@v3      with:        path: |          ~/.cargo/bin/          ~/.cargo/registry/index/          ~/.cargo/registry/cache/          target/        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}    - name: Build      run: cargo build --verbose    - name: Run tests      run: cargo test --verbose


Key points:

  • hashFiles('**/Cargo.lock'): The cache is invalidated only when Cargo.lock changes.
  • path: We cache binaries, the registry index, and the target folder.
  • Restoration: If the key matches, the cache is restored, and cargo skips downloading.


Multi-Platform Build



Rust supports many platforms. To ensure your code works everywhere, use a build matrix:



jobs:  build:    strategy:      matrix:        os: [ubuntu-latest, windows-latest, macos-latest]    runs-on: ${{ matrix.os }}    steps:    - uses: actions/checkout@v4    - name: Install Rust      uses: dtolnay/rust-toolchain@stable                

Blogs

Book Recommendations