Skip to content

CI/CD for Applications

First PublishedByAtif Alam

A CI/CD (Continuous Integration / Continuous Delivery) pipeline automates the path from code commit to production.

The goal is to make deployments fast, repeatable, and safe—so shipping a change is routine, not a high-risk event.

This page covers “application” CI/CD.

For infrastructure pipeline design, see IaC Best Practices — CI/CD for Infrastructure.

A typical pipeline has these stages:

StagePurposeFails If
BuildCompile code, resolve dependencies, produce artifactCompilation error, missing dependency
Unit testsVerify individual components in isolationTest failure
Integration testsVerify components work together (APIs, databases, queues)Contract or behavior failure
Static analysisLint, security scan, code quality checksPolicy violation, vulnerability found
Artifact publishStore the build artifact (container image, binary, package)Registry or storage failure
Deploy to stagingDeploy artifact to a pre-production environmentDeploy failure, health check failure
Smoke / acceptance testsVerify critical paths work in stagingKey user flows broken
Deploy to productionDeploy artifact to production using your delivery strategyDeploy failure, SLI degradation

Not every pipeline needs every stage.

Start with build, test, and deploy; add stages as your confidence and tooling mature.

A quality gate is a check that must pass before the pipeline advances. Gates prevent bad changes from reaching production.

Common gates:

  • Test pass rate — All unit and integration tests must pass. No exceptions.
  • Code coverage threshold — Coverage must not drop below a minimum (e.g. 80%). Prevents shipping untested code.
  • Security scan — No critical or high vulnerabilities in dependencies or code. Block the deploy until resolved.
  • Manual approval — A human reviews and approves before production deploy. Common for regulated environments or high-risk changes.
  • SLO check — If the service is already burning error budget too fast, block new deploys until the budget recovers. See Error Budgets.

Build once, deploy the same artifact to every environment. This eliminates “works on my machine” and “works in staging” problems.

  • Build produces an immutable artifact (container image, versioned binary).
  • Promote that same artifact from staging → production. Don’t rebuild for production.
  • Tag or label artifacts with version, commit SHA, and build timestamp for traceability.
  • Retain previous artifacts so you can roll back quickly. See Feature Flags and Rollback.

Most teams use at least two environments:

  • Staging / pre-production — Mirrors production as closely as possible. Used for integration tests, smoke tests, and manual verification.
  • Production — Real users, real traffic.

Some teams add:

  • Development — Shared environment for feature integration before staging.
  • Ephemeral / preview — Spun up per pull request or per feature branch, torn down after merge. Good for testing in isolation without blocking shared environments.

The key principle: production and staging should be as similar as possible in configuration, data shape, and infrastructure. Differences between environments are a source of “works in staging, breaks in prod” incidents.

See IaC Best Practices — Environments and Promotion for the infrastructure side.

Define your pipeline in version-controlled files (e.g. CI config files). This gives you:

  • Auditability — Who changed the pipeline, when, and why.
  • Repeatability — The pipeline behaves the same way every time.
  • Review — Pipeline changes go through the same code review process as application code.