Skip to content

Continuous Delivery and Release#

Four terms are routinely used as if they were one: continuous integration, continuous delivery, continuous deployment, and continuous release. They are not interchangeable, and the difference between them is not academic — it decides where a human still makes a call, what a pipeline is allowed to do without being asked, and what "done" means for a change.

This page draws the distinction and records the decisions that follow from it. The wider family of always-on practices, and where each term originates, is covered in Continuous Practices; this page is about the delivery end of that family in operational detail.

The distinction#

Each practice extends the one before it. The pipeline is the same spine every time; what changes is how far along it a change travels without a human.

Practice What it means Where it stops
Continuous integration Every change is merged into the mainline frequently and verified there A verified mainline. Nothing is packaged for release.
Continuous delivery Every verified change is packaged and proven deployable, so the mainline is releasable at all times A releasable artifact. Shipping is a business decision a human makes.
Continuous deployment The manual gate is removed — a verified change deploys itself Deployed. Whether users see it is a separate question.
Continuous release Users can now see the change Released to users.

The one-line version: delivery means ready to ship the moment a human decides; deployment means it ships itself; release means users can see it. Deploying is not releasing.

flowchart LR
  commit[Commit] --> pre[Pre-commit] --> build[Build] --> test[Test] --> package[Package] --> deploy[Deploy] --> release[Release to users]

Continuous integration covers Commit → Test. Continuous delivery extends to Package, and stops. Continuous deployment extends to Deploy automatically. Continuous release extends to Release to users — which, once deployment and release are decoupled by a flag or a progressive rollout, is a decision about exposure rather than about a pipeline.

The final step is the one most often skipped in discussion, and it is the only one the user experiences. A change sitting deployed behind a disabled flag has shipped nothing.

Shift left: pre-commit is CI running locally#

The first box on that spine is not decoration. A pre-commit hook runs the fast slice of CI on the contributor's machine — the same linters and formatters the pipeline will run, executed before the commit exists.

That makes pre-commit and CI the same gate at two distances, not two different gates. The pipeline remains authoritative, because a local run can be skipped and a required check cannot; the local run exists so that the overwhelming majority of failures are found in seconds rather than minutes. See Pre-Commit.

Design decisions#

Four decisions turn the distinction above into something a pipeline can implement.

D1 — Build once, decided per artifact type#

The classic rule is build once, promote the same artifact. It holds across the pull-request-to-main boundary only for artifacts that have an external addressable identity independent of their version. Where the version is embedded in the artifact, promotion is impossible and the artifact MUST be rebuilt.

Artifact Across the PR → main boundary Why
Container image Promote Addressed by digest; a tag is metadata attached afterwards
Stored infrastructure plan Promote The plan is the reviewed artifact; rebuilding it invalidates the review
Composite action referenced by tag Promote Identity is the git ref, not a built file
Compiled binary Rebuild Version is compiled in
Module manifest Rebuild Version is a field inside the manifest
Package manifest for a language registry Rebuild Version is a field inside the manifest

The rule of thumb: external identity means promote, embedded version means rebuild. A promoted artifact behaves like continuous delivery — the thing that was reviewed is the thing that ships. A rebuilt artifact behaves like continuous deployment — the pipeline reproduces it from a verified source, and reproducibility is what carries the guarantee instead.

D2 — Version signals feed in, the decision is reviewed at the PR gate#

Several signals suggest what kind of change a pull request contains: the shape of the diff, whether tests were added or changed, the commit messages, and an AI-assisted reading of the change. Those signals MUST be treated as input. The resolved release decision comes from an explicit owned label or the repository's configured default, and its suitability for the audience is reviewed at the pull-request gate.

A configured default is a prior policy decision, not an omission to interpret later. The pull request records the effective level and its source, and review confirms that the level fits the declared user/integrator impact. A missing decision fails a required CI check and blocks merge; publication does not discover the missing decision only after integration.

D3 — Prerelease by default, stabilized on merge#

A topic-branch build authorized for release MUST be published as a prerelease. The stable version is cut on merge, from the resolved release decision.

A prerelease version (1.3.0-add-widgets.1) sorts below every stable version, which is the entire mechanism: a consumer who has not opted in cannot resolve it, so publishing early is free. Contributors and reviewers get a real, installable artifact to test against for the whole life of the pull request, and nobody has to build it by hand.

The stable release is then not a separate act of packaging — it is the same content with the prerelease suffix removed, at the moment the change becomes part of the mainline.

D4 — Recovery is roll-forward only#

A published version MUST NOT be altered or replaced. Recovery from a bad release is a new, higher version.

This is SemVer §3: release contents are immutable once published. The practical argument is stronger than the formal one. A consumer who has already resolved 2.4.1 will not re-resolve it, so replacing its contents produces two different artifacts answering to one name — and the consumer who was fast enough to install the first one now has a build nobody can reproduce. Yanking has the same problem in reverse: it breaks every lockfile that pinned it.

So a broken release stays published and a fix ships as 2.4.2. The bad version is recorded as bad in its release notes rather than erased.

References#

Where this connects#