GitLab Pipeline Waiting for Manual Approval
In a continuous delivery workflow, it is often necessary to require manual confirmation before proceeding with a production deployment. This post walks through how to implement that, including a pitfall I ran into along the way.
How to Implement It
The solution is actually quite simple, as shown below:
1 | waiting-for-approval: |
There are two key fields here: when and allow_failure.
when
This field specifies under what conditions the job should run. The accepted values are:
on_success(default): The job runs only after all jobs in the previous stage have succeeded, or all jobs in the previous stage are configured withallow_failure: true.manual: The job is triggered manually.always: The job always runs, regardless of whether the previous stage succeeded or failed.on_failure: The job runs when at least one job in the previous stage has failed.delayed: The job runs after a specified delay.never: The job never runs.
allow_failure
This field determines whether the pipeline should continue when the current job fails. The value can be true or false.
Pay close attention to the default value — this is where the pitfall lies.
- When the job has
when: manual, the default value istrue. - When the job has
when: manualand also configuresrules, the default value isfalse. - In all other cases, the default value is
true.
The Pitfall
Hitting the Problem
I wanted to implement a pipeline that looks like this:

My .gitlab-ci.yml was as follows:
1 | image: alpine |
The actual execution result was:

I hadn’t clicked approval yet — so why did deploy-to-prod already run? And the pipeline status showed passed — how was it already passed?

What Went Wrong?
I went back to the documentation — Keyword reference for the .gitlab-ci.yml file | GitLab — and under Additional details found the following:
The default behavior of
allow_failurechanges totruewithwhen: manual. However, if you usewhen: manualwith[rules](https://docs.gitlab.com/ee/ci/yaml/#rules),allow_failuredefaults tofalse.
Mystery solved!
I also found another relevant documentation page: Choose when to run jobs | GitLab, which covers how to create a job that must be triggered manually.
The Fix
Update .gitlab-ci.yml as follows:
1 | image: alpine |
The updated execution results:
