There is no shortage of maturity models. Most of them are a way for a consultant to produce a colourful diagram and a twelve-month contract. This one is deliberately smaller and aimed at a single question: what is the single thing to fix next?

Stage one: manual

Deployments happen by a person running commands, often from a laptop, following a document that is usually out of date. There is no environment parity. Nobody can say what is running in production without looking at it.

This stage is more common in organisations that would describe themselves as “fully automated”. The build is automated. The deploy is not. That distinction matters enormously and is worth checking before anything else.

How to tell

Ask someone to deploy a hotfix to production while you watch. If they need to find a runbook, check a wiki page, or recall the correct sequence from memory, you are here.

Stage two: scripted

There is a script, and it works. Deployments are at least reproducible, and usually faster and less error-prone than before. But the script is run manually, it lives somewhere slightly awkward, and it assumes the person running it knows the context.

Real progress from stage one. Also where a lot of teams stall, because the script works and nobody feels enough pain to justify the next step.

Stage three: automated pipeline

Code commits trigger a build, tests, and a deployment to at least one non-production environment without human involvement. Deployments to production may still be approved by a person, which is fine — that is not a failure of automation, it is a decision about risk.

This is the stage most teams describe themselves as being at when they are not. The test is specific: does a commit to main cause a build and a test run with no human involved at any point? If a developer must click something in a browser to start the process, you are at stage two with extra steps.

Stage four: continuous delivery

Every change that passes the gates is capable of going to production immediately and safely. Deploying is a decision, not a project. Small, frequent, reversible.

The distinguishing capability is rollback. Not the intention to roll back, and not a documented procedure for it — an actual tested, rehearsed ability to return to the previous state in minutes, including the data layer.

Most of the work of getting here is unglamorous: environment parity, making configuration injectable rather than baked in, and automating the database changes that everyone is afraid to touch.

Stage five: continuous deployment

Every change that passes the gates goes to production automatically. No approval, no ceremony. Humans decide what gets built, not whether it ships.

This is a legitimate target for a small number of teams and a bad target for most. It requires very high automated test coverage, extremely low change failure rates, and real confidence in observability. Forced there prematurely, it produces a fast path to production problems.

Worth saying plainly

Stage five is not the finish line, and aiming for it is not maturity. A team that deploys weekly, safely, with a five-minute rollback and understands its system is doing well. Do not let anyone tell you otherwise.

How to find your actual stage

Ask these four questions and take the lowest answer. Do not average them, and do not let the most senior person in the room answer for everyone.

  1. Does a commit trigger a build and test run with no human action?
  2. Can you deploy to a production-like environment from any developer machine, on demand?
  3. Have you performed a rollback in the last six months, and did it work?
  4. Can you name the current production version for any given service, right now?

If question three is a no, you are at stage three regardless of what the CI configuration implies. The configuration describes the intended process; the rollback test describes the real one.

What actually blocks the next stage

It is almost never the build tool.

Blocked atUsually the real blocker
Manual → scriptedNobody owns the deployment process, so nobody is accountable for writing it down
Scripted → automatedEnvironment drift. Dev, test and prod genuinely differ, so the script only works in one of them.
Automated → deliveryDatabase migrations are not reversible, so deploying feels irreversible
Delivery → continuousTest coverage is too low to trust the gates, so the gates get bypassed

Each of these is a design problem, not a tooling problem, and each is solvable without buying anything.

The trap of the maturity model

Used well, a model like this tells you where to look next. Used badly, it becomes a score to report upwards, and the fastest way to improve a score is to describe the current state more generously.

The most useful question is not “which stage are we at” but “what did the last production incident teach us about our process?” That answer is always concrete, always actionable, and never flattering.