CI/CD for Rust Projects: GitHub Actions Advanced Level

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 Advanced CI/CD is Important for Rust Projects



A basic CI/CD pipeline for Rust is good, but in real projects, especially those with multiple platforms, dependencies, and the need for fast feedback, a simple cargo test is not enough. Advanced GitHub Actions configuration allows you to reduce build time by 2-3 times, automatically check code on different architectures, publish crates, and perform linting.



In this article, we will cover advanced techniques: dependency caching, build matrices for Windows/macOS/Linux, parallel test execution, publishing to crates.io, and integration with Clippy.



1. Build Time Optimization: Caching and Incremental Compilation



The most expensive operation in CI for Rust is compiling dependencies. Without caching, each run will download and build all crates from scratch. The solution is to use the built-in GitHub Actions cache.



Basic target Directory Caching



jobs:  build:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions-rust-lang/setup-rust-toolchain@v1      - name: Cache Rust dependencies        uses: actions/cache@v3        with:          path: |            ~/.cargo/registry            ~/.cargo/git            target          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}      - run: cargo build --release


Key point: the cache key includes the Cargo.lock hash. If dependencies haven't changed, the cache is restored instantly.



Advanced Cache Separation for Tests and Builds



For large projects, it makes sense to separate the cache for cargo build and cargo test to avoid rebuilding test binaries during a release build:



- name: Cache cargo build  uses: actions/cache@v3  with:    path: |      ~/.cargo/registry      ~/.cargo/git      target/debug/.fingerprint      target/debug/build    key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.lock') }}


2. Build Matrix: Testing on All Platforms



Rust compiles for many platforms. To ensure correct operation on Windows, macOS, and Linux, we use a matrix strategy.



Example Matrix for Three OSes



jobs:  test:    strategy:      matrix:        os: [ubuntu-latest, windows-latest, macos-latest]        toolchain: [stable, beta]        features:          - default          - all    runs-on: ${{ matrix.os }}    steps:      - uses: actions/checkout@v4      - uses: actions-rust-lang/setup-rust-toolchain@v1        with:          toolchain: ${{ matrix.toolchain }}      - name: Run tests        run: cargo test --features ${{ matrix.features }}


This approach automatically creates 6 parallel jobs (3 OSes × 2 toolchains). You can add checks for nightly, arm64 architectures, or cross-compilation for WASM.



Excluding Unnecessary Combinations



strategy:  matrix:    os: [ubuntu-latest, windows-latest, macos-latest]    toolchain: [stable, nightly]    exclude:      - os: macos-latest        toolchain: nightly  # Don't test nightly on macOS


3. Linting, Formatting, and Security



In addition to tests, advanced CI includes static analysis. Let's add checks for clippy, rustfmt, and cargo-audit for vulnerabilities.



Separate Job for Linting



lint:  runs-on: ubuntu-latest  steps:    - uses: actions/checkout@v4    - uses: actions-rust-lang/setup-rust-toolchain@v1      with:        components: clippy, rustfmt    - name: Check formatting      run: cargo fmt --check    - name: Clippy with warnings as errors      run: cargo clippy -- -D warnings


Security Check

Blogs

Book Recommendations