CI Pipeline Design and Quality Gates

A continuous integration pipeline is the road every change travels to production. Its design decides how quickly developers learn they broke something, how much a green build actually means, and whether the thing deployed to production is the thing that was tested. Most pipelines start as one job that runs everything and then decay: forty minutes per run, flaky tests retried until they pass, artifacts rebuilt separately for each environment, and security scans that print warnings nobody reads.

A well-designed pipeline separates stages with different jobs — fast feedback, integration validation, artifact production, and promotion — and puts explicit quality gates between them: automated checks with clear pass criteria that genuinely block. When gates are trusted, a green build is a decision, not a hope.

TL;DR

Quick Example

A GitHub Actions workflow with three stages. Pull requests get fast feedback and integration tests; merges to main also produce one container image with build provenance, which deployment workflows later promote by digest.

Each stage only runs when the cheaper stage before it passes, and nothing later in the release process rebuilds the image.

Core Concepts

Pipeline Stages

Fast feedback runs on every push; slower stages can run on pull requests that pass the first stage, on the merge queue, or on main. What matters is that every stage has a clear job and a budget someone watches.

Quality Gates

A quality gate is an automated check with an explicit pass criterion that blocks the change from moving forward. Gates that only warn are reports, and reports get ignored.

Good gates measure new problems in the change, not the whole codebase's history. A gate that fails because of a vulnerability someone else introduced last year trains people to bypass it.

Build Once, Promote Many

Rebuilding for each environment produces different binaries: dependency versions resolve differently, base images update, build flags drift. The artifact that passed staging is then not the artifact running in production. Build once, identify the artifact by its content digest, and promote that digest through environments, changing only configuration — see Configuration and Environment Management.

Keeping Main Green

Required status checks stop red pull requests from merging, but two individually green pull requests can still break main when combined. A merge queue (GitHub merge queue, GitLab merge trains) tests each change on top of the changes ahead of it before merging, so main stays releasable at every commit.

Making Pipelines Fast

Flaky Tests

A flaky test passes and fails on the same code. A few flaky tests teach a team that red builds are probably noise, and real failures start getting retried away.

Automatic retries can be a temporary aid if each retry is recorded and reviewed, but blanket retries of the whole suite hide real bugs. Many root causes are covered in Test Data and Environment Management.

Securing the Pipeline

CI systems hold deployment credentials and produce the software users run, which makes them attractive targets.

See GitHub Actions Security and Software Supply Chain Security.

Best Practices

Run the Same Commands Locally and in CI

Keep pipeline steps as thin wrappers around project scripts (npm run lint, make test). Developers can reproduce any failure locally, and switching CI providers becomes easy.

Give Every Gate an Owner

Someone must decide thresholds, fix false positives, and retire gates that no longer earn their cost. A gate that is regularly overridden is broken; repair it or remove it.

Ratchet Legacy Codebases

When an existing codebase fails a new gate, record a baseline and block only regressions. Lower the baseline as issues are fixed until the gate can apply to everything.

Report Failures Where People Look

Annotate pull requests with the failing file and line, summarize results at the top of the run, and link to logs. Developers should understand a failure in seconds.

Common Mistakes

Rebuilding for Each Environment

Retrying Until Green

Unpinned Actions With Broad Tokens

Gates on Total Coverage

FAQ

How fast should CI be?

Fast feedback within about ten minutes of pushing, so developers stay in context, and the full set of merge checks within about twenty to thirty minutes. Beyond that, people batch changes, switch tasks, and stop waiting for results.

What is a quality gate?

An automated check with a defined pass criterion that blocks a change from merging, releasing, or being promoted until it passes — for example "no new critical vulnerabilities" or "canary error rate within the SLO". Unlike a report, a gate changes what happens next.

Should code coverage be a gate?

Coverage of changed lines is a reasonable gate; total coverage percentages usually are not. Coverage shows which code ran, not whether tests assert anything meaningful, so pair it with code review of the tests themselves.

What is a merge queue?

A queue that tests each pull request together with the changes merging ahead of it, and only merges it if that combination passes. It prevents two individually green changes from breaking the main branch when combined.

Why build once and promote?

Because the artifact you tested should be the artifact you run. Rebuilding introduces drift in dependencies and base images, and makes it impossible to say exactly what is in production. Promotion by digest gives every environment the same bytes.

Related Topics

References