Building CI/CD Pipelines That Teams Actually Trust
A pipeline people ignore or bypass is worse than no pipeline at all.

A pipeline people ignore or bypass is worse than no pipeline at all.

There is a specific moment when a continuous integration pipeline stops working, and it has nothing to do with the pipeline breaking. It is the moment someone says, in a completely normal tone of voice, just re-run it, that test is flaky.
From then on, every red build is ambiguous. Is it broken, or is it that again? People stop reading failures and start re-running them. Eventually someone merges past a genuine failure because everyone had learned that red does not necessarily mean anything.
That is the real subject of this article. The tooling question — which CI service, which deployment target — is much easier than the trust question, and considerably less important.

The single most important property of a pipeline is how long it takes to tell you something useful. Under five minutes, developers wait for the result and fix things immediately. Past fifteen, they context-switch to something else, and the fix arrives an hour later with the original reasoning already forgotten.

Past thirty minutes, people start batching changes to avoid the wait, which makes each change larger and each failure harder to diagnose. The pipeline has begun actively degrading the work it was meant to protect.
This deserves to be stated more strongly than it usually is. A test that fails intermittently without a code change is not a minor annoyance. It is an attack on the credibility of every other test in the suite.
The mechanism is straightforward. One flaky test teaches the team that red sometimes means nothing. That lesson generalises immediately, because nobody memorises which specific test is unreliable. Within weeks, the response to any failure is a re-run.
Adopt a same-day rule: a test that fails intermittently is quarantined out of the required suite within 24 hours, with a ticket to fix or delete it. A quarantined test protects nothing but is honest about it. A flaky required test actively teaches people to ignore failures.
The usual causes are worth knowing, because they repeat: timing assumptions and arbitrary sleeps, tests sharing state or a database, dependence on execution order, real network calls, and anything involving the current time or a timezone.
| Stage | What runs | Typical time | Blocks merge? |
|---|---|---|---|
| Pre-commit | formatting, obvious lint | seconds, locally | no, but keeps noise out |
| On every push | lint, types, unit tests | under 5 minutes | yes |
| On pull request | integration tests, build | under 15 minutes | yes |
| After merge | end-to-end, deploy to staging | as long as needed | no, but alerts |
| Nightly | full suite, security scans, performance | hours | no, but tracked |
The principle is that the checks blocking a merge should be fast and reliable, while slow or occasionally noisy checks run where they inform rather than obstruct. A required check that is slow and flaky is the worst combination available, and it is remarkably common.
The most reliable indicator of a healthy engineering organisation is that deploying is unremarkable. It happens several times a day, nobody schedules it for a Thursday evening, and it does not require a person with special knowledge.
That state comes from frequency, not caution. Small, frequent deployments each carry little risk and are easy to diagnose when something goes wrong — one change, one suspect. A monthly release bundling 200 changes concentrates all the risk into one evening and makes attributing a problem genuinely hard.

Everyone optimises deployment speed. The number that actually determines your worst incident is how quickly you can undo one.
If rolling back means a full redeploy of the previous version, taking eleven minutes, then every bad deploy is at least an eleven-minute outage. If it means flipping traffic back to a version still running, it is seconds.
A team's pipeline had grown to twelve minutes: every push ran the full test suite, including browser tests, against a freshly built container with no dependency caching.
They restructured it. Lint and type checks ran first and failed in about twenty seconds. Unit tests ran in parallel across four workers with a warm dependency cache. Browser tests moved to run on pull requests only, and the full cross-browser matrix moved to nightly.
Feedback on a typical push dropped to about ninety seconds. The measurable consequence was not just time saved — the number of pull requests merged with a failing check fell to nearly zero, because developers were now still watching when the result arrived.
A pipeline that can be skipped will be skipped, and always during the incident where the checks mattered most. If an emergency bypass exists it should be loud: an audit trail, a notification to the team, and a required follow-up. Silent bypasses become the normal path within a few months.
When a build fails, someone has to work out why from the output. A failure that says Error: process exited with code 1 after 400 lines of log is a puzzle rather than a message.
Surface the specific failing test and its assertion at the top. Link straight to the relevant log section. If a check has a common cause — a missing environment variable, an out-of-date lockfile — say so in the failure text. Every minute spent making failures legible is repaid many times, because failures are read far more often than pipeline configuration is written.
The pipeline's job is not to run tests. It is to tell a person, quickly and unambiguously, whether their change is safe.
— The definition worth designing against

Optimise for time-to-feedback under five minutes. Treat flaky tests as an emergency and quarantine them within a day. Stage checks so required ones are fast and reliable. Deploy small and often. Invest in rollback speed and backwards-compatible migrations. Make failure output legible, and make bypasses loud.
A pipeline is a social contract as much as a technical system. It works when developers believe that green means safe and red means stop — and both halves of that belief are earned by consistency, not by configuration.

Protect the belief and the pipeline pays for itself. Let it erode and you have an expensive process that everyone quietly routes around. If your deployments run in containers, our explainer on how containers actually work covers the layer underneath.
Tap a star to share what you thought.
No ratings yet
Continuous integration means every change is automatically built and tested against the shared main branch. Continuous delivery means every change that passes is automatically prepared for release, so deploying becomes a decision rather than a project.
Aim for useful feedback in under five minutes on every push. Beyond fifteen minutes developers context-switch away and fixes arrive much later; beyond thirty they start batching changes, which makes every failure harder to diagnose.
Because they teach the team that a red build might mean nothing. That lesson generalises to every test, so people stop reading failures and start re-running them — and eventually a genuine failure gets merged past.
Quarantine it out of the required suite within a day and raise a ticket to fix or delete it. A quarantined test protects nothing but is honest; a flaky required test actively erodes trust in every other check.
As often as changes are ready — several times a day is a reasonable target for most web services. Small frequent deploys each carry little risk and are trivially diagnosable, while large infrequent releases concentrate risk into one event.
Because rollback time is the floor on your worst incident duration. If undoing a bad deploy takes eleven minutes, every bad deploy is at least an eleven-minute outage, regardless of how quickly you shipped it.
Make them backwards compatible: the previous version of the application should continue to work against the new schema. Add columns before using them, remove them in a later release, and avoid renames that break both directions at once.
An emergency path is reasonable, but it must be loud — audited, announced to the team and requiring follow-up. Silent bypasses quietly become the default route within a few months, at which point the pipeline protects nothing.
Sign in to join the conversation.
Loading responses…
Have a story, idea, or something valuable to share? Join The Blog Story for free, publish your content, reach more readers, and earn a share of advertising revenue from eligible content.
Create quality content. Grow your audience. Grow your earning potential.