CI Basics
CI Is Your Automated Reviewer
Continuous Integration (CI) is not just about running tests. It is your automated reviewer that ensures every commit meets baseline quality before reaching production. A clean CI pipeline prevents broken builds, inconsistent formatting, lint regressions, and hidden test failures.
Production mindset:
- CI must be deterministic
- CI must be fast enough to run on every PR
- CI failures must be actionable
Minimum Viable CI for Rust
A practical production baseline includes:
- cargo build
- cargo fmt check
- cargo clippy (warnings as errors)
- cargo test
Step 1: Build Validation
Always ensure the project compiles in CI.
cargo build --workspace --all-targets --locked
Use the --locked flag to guarantee Cargo.lock is respected and dependency versions are reproducible.
Step 2: Formatting Check
cargo fmt -- --check
This ensures contributors run rustfmt locally.
Step 3: Linting
cargo clippy --workspace --all-targets -- -D warnings
Treat warnings as errors to prevent slow accumulation of technical debt.
Step 4: Run Tests
cargo test --workspace --all-targets --locked
Production rule: CI must not rely on external services unless explicitly controlled (e.g., test containers).
Example GitHub Actions Workflow
Minimal workflow file:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build
run: cargo build --workspace --all-targets --locked
- name: Format
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy --workspace --all-targets -- -D warnings
- name: Test
run: cargo test --workspace --all-targets --locked
This is intentionally minimal and production-safe.
Reproducibility and Toolchain Pinning
To avoid surprises when Rust updates, pin the toolchain.
# rust-toolchain.toml [toolchain] channel = "1.76.0"
Production rule: do not let CI randomly change compiler versions.
Fail Fast and Clear
Order CI steps from fastest to slowest:
- Format
- Clippy
- Build
- Tests
This reduces wasted compute time when formatting or linting already fails.
Parallel Jobs (Optional Later)
As your project grows, you may split jobs:
- Lint job
- Test job
- Coverage job
But start simple. Complexity in CI is a production risk if not needed.
Common Production Pitfalls
- Allowing CI to pass with warnings
- Using nightly toolchain unintentionally
- Running tests that depend on external APIs
- Slow CI discouraging developers from running it locally
- Ignoring failing CI temporarily and merging anyway
Production Checklist
- cargo build with --locked
- cargo fmt check
- cargo clippy with -D warnings
- cargo test for workspace
- Pinned Rust toolchain
- CI runs on every PR
A minimal, strict CI pipeline keeps your Rust project production-grade. It ensures that code style, correctness, and compilation are guaranteed before any change reaches main.