Workflow orchestration
Workflows in CircleCI are used to orchestrate jobs. Workflows have options to control run order, scheduling, and access to resources. This page explains how to configure workflows to suit your project. Optimizing your workflows can increase the speed of your software development through faster feedback, shorter reruns, and more efficient use of resources.
Overview
A workflow is a set of rules for defining a collection of jobs and their run order. Create workflows to orchestrate your jobs using the options described on this page.
With workflows, you can:
-
Run and troubleshoot jobs independently with real-time status feedback.
-
Schedule workflows for jobs that should only run periodically.
-
Fan-out to run multiple jobs concurrently for efficient version testing.
-
Fan-in to deploy to multiple platforms.
-
Catch failures in real-time and rerun only failed jobs.
Workflows configuration examples
For a full specification of the workflows key, see the Workflows section of the configuration reference.
|
Concurrent job execution
The example in this section shows the default workflow orchestration model of concurrent jobs. Concurrent jobs are defined as follows:
-
Use the
workflowskey. -
Name the workflow, in this case,
build_and_test. -
Nest the
jobskey with a list of job names that are defined in the configuration file. In this example the jobs have no dependencies defined, so they run concurrently.
| Using Docker? Authenticating Docker pulls from image registries is recommended when using the Docker execution environment. Authenticated pulls allow access to private Docker images, and may also grant higher rate limits, depending on your registry provider. For further information see Using Docker authenticated pulls. |
jobs:
build:
docker:
- image: cimg/base:2023.06
steps:
- checkout
- run: <command>
test:
docker:
- image: cimg/base:2023.06
steps:
- checkout
- run: <command>
workflows:
build_and_test:
jobs:
- build
- test
See the Sample concurrent workflow config for a full example.
When using workflows, note the following best practices:
-
Move the quickest jobs up to the start of your workflow. For example, lint or syntax checking should happen before longer-running, more computationally expensive jobs.
-
Using a "setup" job at the start of a workflow can be helpful to do some preflight checks and populate a workspace for all the following jobs.
| Refer to the Optimization reference for tips to improve your configuration. |
Sequential job execution
This example shows a workflow with four sequential jobs. Each job waits to start until the "required" job finishes successfully, as illustrated in the following diagram:
This configuration snippet is an example of a workflow configured for sequential jobs:
workflows:
build-test-and-deploy:
jobs:
- build
- test1:
requires:
- build
- test2:
requires:
- test1
- deploy:
requires:
- test2
Define job dependencies using the requires key. A job must wait until all upstream jobs in the dependency graph have run. In this example, the deploy job runs when the build, test1 and test2 jobs complete successfully:
-
The
deployjob waits for thetest2job -
The
test2job waits for thetest1job -
The
test1job waits for thebuildjob
See the Sample Sequential Workflow config for a full example.
Fan-out/fan-in workflow
This example workflow has a fan-out/fan-in structure, as follows:
-
A common build job is run.
-
The workflow fans-out to run a set of acceptance test jobs concurrently.
-
The workflow fans-in to run a common deploy job.
This configuration snippet is an example of a workflow configured for fan-out/fan-in job execution:
workflows:
build_accept_deploy:
jobs:
- build
- acceptance_test_1:
requires:
- build
- acceptance_test_2:
requires:
- build
- acceptance_test_3:
requires:
- build
- acceptance_test_4:
requires:
- build
- deploy:
requires:
- acceptance_test_1
- acceptance_test_2
- acceptance_test_3
- acceptance_test_4
In this example, as soon as the build job finishes successfully, all four acceptance test jobs start. The deploy job waits for all four acceptance test jobs to succeed before it starts.
See the Sample Fan-in/Fan-out Workflow config for a full example.
Flexible job dependency
Using requires, you can build complex dependency maps and fan in/out scenarios.
The following example is a configuration snippet of a workflow with four sequential jobs. Each job waits until the "required" job attains a specified status:
workflows:
build-and-deploy:
jobs:
- build
- deploy:
requires:
- build
- release:
requires:
- deploy
- rollback:
requires:
- release:
- failed
- canceled
A job must wait until all upstream jobs in the dependency graph have attained either of the statuses specified under the corresponding requires key. In this example, the following dependencies are configured:
-
The
rollbackjob waits for thereleasejob, and only runs if thereleasejob fails or is canceled. -
The
releasejob waits for thedeployjob, and only runs if thedeployjob is successful. -
The
deployjob waits for thebuildjob, and only runs if thebuildjob is successful.
release job is successful
release job fails:You may want to configure job dependencies that ignore the status/outcome of an upstream job.
In the following example, the dependent job will run once the upstream job attains a terminal state, regardless of the status/outcome:
workflows:
test-and-cleanup:
jobs:
- build
- test:
requires:
- build
- cleanup:
requires:
- test:
- success
- failed
- canceled
-
The
testjob waits for thebuildjob, and only runs if thebuildjob is successful. -
The
cleanupjob waits for thetestjob, and runs regardless of whether thetestjob succeeds, fails, or is canceled.
| Refer to the Requires section of the configuration reference. |
Hold a workflow for a manual approval
Use an approval job to configure a workflow to wait for manual approval before continuing. Anyone who has push access to the repository can approve the job to continue the workflow or cancel to end the workflow. Approve or Cancel either by using the buttons in the CircleCI web app, or via the API.
Some things to keep in mind when using manual approval in a workflow:
-
approvalis a special job type that is configured when listing jobs under theworkflowskey. You do not need to define anapprovaltype job in thejobssection of your configuration. If you do configure steps for a job that is given theapprovaltype in the workflows section, the steps for that job will not be run. Anapprovaljob is only used to hold the workflow for approval, not to run any work. -
The
approvaljob name must be unique and not used by any other job in your configuration. -
The name of the approval job is arbitrary. For example, an approval job can be named
hold,wait,pause, etc. -
All jobs that run after a manual approval job must
requirethe name of theapprovaljob. -
Jobs run in the order defined in the workflow.
-
When the workflow encounters a job with
type: approval, the workflow pauses until action is taken to approve or cancel. -
If approval is granted the workflow continues to process jobs in the order defined in the configuration file.
-
If cancel is granted the downstream jobs are not run.
-
Jobs downstream of an
approvaljob can be restricted by adding a restricted context to those downstream jobs.
The following screenshot demonstrates:
-
A workflow that needs approval.
-
The approval popup.
-
The workflow graph after approval.
By clicking on the approval job’s name (hold, in the screenshot above), an approval dialog box appears. You can approve, cancel, or close the popup without approving.
Configure an approval job
To set up a manual approval workflow, add a job to the jobs list in your workflow with type: approval. For example:
# ...
# << your config for the build, test1, test2, and deploy jobs >>
# ...
workflows:
build-test-and-approval-deploy:
jobs:
- build # your custom job from your config, that builds your code
- test1: # your custom job; runs test suite 1
requires: # test1 will not run until the `build` job is completed.
- build
- test2: # another custom job; runs test suite 2,
requires: # test2 is dependent on the success of job `test1`
- test1
- hold: # <<< A job that will require manual approval in the CircleCI web application.
type: approval # This key-value pair will set your workflow to a status of "Needs Approval"
requires: # We only run the "hold" job when test2 has succeeded
- test2
# On approval of the `hold` job, any successive job that requires the `hold` job will run.
# In this case, a user is manually triggering the deploy job.
- deploy:
requires:
- hold
In this example, the deploy job will not run until the hold job is approved.
Approve a job
To approve a job follow these steps:
-
CircleCI web app
-
API
-
Select the
holdjob in the Workflows page of the CircleCI web app. -
Select Approve.
Using server? If you are using CircleCI server, replace https://circleci.com with your server hostname when interacting with the CircleCI API.
|
-
Set up your API authentication. Steps are available in the API developers guide.
-
You need your workflow ID and the
approval_request_id(which is the job ID for the job requiring approval) to make the API POST request. Depending on your use case, you might be configuring an approval job in a pipeline, or using an external service to approve a job. You can get the required parameters using pipeline values or environment variables, or by receiving webhooks or polling the API. To approve a job, use the approve a job endpoint, for example:curl --request POST \ --url https://circleci.com/api/v2/workflow/<workflow-ID>/approve/<approval_request_id> \ --header "Circle-Token: ${CIRCLE_TOKEN}" \ --header 'content-type: application/json' \
Identify the user who approved a job
To identify the user who approved a job, you can use the CircleCI web app or the API.
-
CircleCI web app
-
API
-
If the user signed up via GitHub, the (non-clickable) avatar of the GitHub user appears next to the approval job. Hovering over that avatar brings up a tooltip with the user’s name as specified in their GitHub/Bitbucket account settings.
-
If the user signed up via email, the anonymous avatar appears next to the approval job; hovering over that avatar brings up a tooltip with the user’s email address.
-
Set up your API authentication. Steps are available in the API developers guide.
-
You need the workflow ID so you can use the get a workflow’s jobs endpoint to get the user ID. You can get the workflow ID using pipeline values or environment variables, or by receiving webhooks or polling the API
curl --request GET \ --url https://circleci.com/api/v2/workflow/<workflow-ID>/job \ --header "Circle-Token: ${CIRCLE_TOKEN}" \ --header 'content-type: application/json' \ -
In the JSON response, take note of the value associated with the
approved_bykey. This is the user ID of the user who approved the job."name" : "hold", "project_slug" : "gh/<org>/<project>", "approved_by" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx", "type" : "approval", "status" : "success", -
Then use the user information endpoint to get the username or email address.
curl --request GET \ --url https://circleci.com/api/v2/user/<user-ID> \ --header "Circle-Token: ${CIRCLE_TOKEN}" \ --header 'content-type: application/json' \-
If the user who approved the job signed up via GitHub or Bitbucket, the response from the user information endpoint will have the following format:
{ "name" : "User’s name as specified in their VCS account settings", "login" : "VCS username", "id" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" } -
If the user who approved the job signed up via email, the response from the user information endpoint will have the following format:
{ "name" : "Email address", "login" : "Email address", "id" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" }
-
| You can find detailed instructions in this support article |
Cancel a job
To Cancel a job follow these steps:
-
CircleCI web app
-
API
-
Select the
holdjob in the Workflows page of the CircleCI web app. -
Select Cancel.
-
Set up your API authentication. Steps are available in the API developers guide.
-
You need your job ID (which is the job ID for the job requiring approval) to make the API POST request. Depending on your use case, you might be configuring an approval job in a pipeline, or using an external service to approve a job. You can get the required parameters using pipeline values or environment variables, or by receiving webhooks or polling the API. To cancel a job, use the cancel a job endpoint, for example:
curl --request POST \ --url https://circleci.com/api/v2/jobs/<job-ID>/cancel \ --header "Circle-Token: ${CIRCLE_TOKEN}" \ --header 'content-type: application/json' \
In this example, the purpose of the hold job is to wait for approval to begin deployment. A job can be approved for up to 90 days after it starts.
Scheduling a workflow
| Scheduled workflows are not available for projects integrated through the GitHub App, GitLab or Bitbucket Data Center. |
| The scheduled workflows feature does not support dynamic configuration. If you use dynamic configuration you will need to use schedule triggers for scheduling. More information can be found in this support article. |
By default, a workflow runs on every push, or based on the event rules you have set up for your trigger ( or ). To trigger a workflow on a schedule, add the triggers key to the workflow and specify a schedule. Scheduled workflows use the cron syntax to represent Coordinated Universal Time (UTC).
Running a workflow for every commit for every branch can be inefficient and expensive. Scheduling a workflow is an alternative to building on every commit. You can schedule a workflow to run at a certain time for a specific branch or branches. Consider scheduling workflows that are resource-intensive or that generate reports on a schedule rather than on every commit.
| A scheduled workflow will run on a schedule only. A scheduled workflow will not be run on commits to your code. |
If you do not configure any workflows in your .circleci/config.yml, an implicit workflow is used. If you configure a scheduled workflow the implicit workflow is no longer run. If you want to build on every commit you must add your workflow to your configuration file.
| When you schedule a workflow, the workflow will be counted as an individual user seat. |
Build every night
In the example below, the nightly workflow is configured to run every day at 12:00am UTC. The cron key is specified using POSIX crontab syntax. See the crontab man page for cron syntax basics. The workflow runs on the main and beta branches.
| Scheduled workflows may be delayed by up to 15 minutes. This delay is to maintain reliability during busy times, such as 12:00am UTC. Do not assume that scheduled workflows start with to-the-minute accuracy. |
workflows:
commit:
jobs:
- test
- deploy
nightly:
triggers:
- schedule:
cron: "0 0 * * *"
filters:
branches:
only:
- main
- /^release\/.*/
jobs:
- coverage
In the above example:
-
The
commitworkflow has notriggerskey and runs on everygit push. -
The
nightlyworkflow has atriggerskey and runs on the specifiedschedule, which is daily, and only runs on themainbranch, as well as any branch that startsrelease/.
Specifying a valid schedule
A valid schedule requires:
-
A
cronkey -
A
filterskey -
The
branchesfilter must be present
The value of the cron key must be a valid crontab entry.
The following are not supported:
-
Cron step syntax (for example,
*/1,*/20). -
Range elements within comma-separated lists of elements.
-
Range elements for days (for example,
Tue-Sat).
Use comma-separated digits instead.
Example invalid cron range syntax:
triggers:
- schedule:
cron: "5 4 * * 1,3-5,6" # < the range separator with `-` is invalid
filters:
branches:
only:
- main
Example valid cron range syntax:
triggers:
- schedule:
cron: "5 4 * * 1,3,4,5,6"
filters:
branches:
only:
- main
The value of the filters key must be a map that defines rules for execution on specific branches.
For more details, see the branches section of the CircleCI configuration reference.
For a full configuration example, see the Sample Scheduled Workflows configuration.
Using contexts to share and secure environment variables
In a workflow, you can use a context to securely provide environment variables to specific jobs. Contexts allow you to define environment variables at the organization level and control access to them through security restrictions. Using contexts, sensitive data like API keys or credentials are securely shared with only the jobs that require them. Sensitive data in contexts will not be exposed in your config file.
The following example shows a workflow with four sequential jobs that each use a context to access environment variables. See the Contexts page for detailed instructions on this setting in the application.
The following config.yml snippet is an example of a sequential job workflow configured to use the environment variables defined in the org-global context:
workflows:
build-test-and-deploy:
jobs:
- build
- test1:
requires:
- build
context: org-global
- test2:
requires:
- test1
context: org-global
- deploy:
requires:
- test2
The test1 and test2 jobs have access to environment variables stored in the org-global context if the pipeline meets the restrictions set for the context, for example:
-
Was the pipeline triggered by a user who has access (is in the relevant org/security group etc.)?
-
Does the project have access to the context? By default all projects in an organization have access to contexts set for that organization, but restrictions on project access can be configured.
-
Does the pipeline meet the requirements of any expression restrictions set up for the context?
Use conditional logic in workflows
You may use a when clause (the inverse clause unless is also supported) under a workflow declaration with a logic statement to determine whether or not to run that workflow.
Workflows are always run unless there is a when or unless filter that prevents the workflow from being run. If you want a workflow to run in every pipeline, do not add a when or unless filter.
The example configuration below uses a pipeline parameter, run_integration_tests to drive the integration_tests workflow.
version: 2.1
parameters:
run_integration_tests:
type: boolean
default: false
workflows:
integration_tests:
when: << pipeline.parameters.run_integration_tests >>
jobs:
- mytestjob
jobs:
This example prevents the workflow integration_tests from running unless the run_integration_tests pipeline parameter is true. For example, when the pipeline is triggered with the following in the POST body:
{
"parameters": {
"run_integration_tests": true
}
}
For more examples of using conditional logic in your workflows, see the Orchestration cookbook.
Using filters in your workflows
The following sections provide examples for using filters in your workflows to manage job execution.
You can filter workflows by branch, git tag, or neither. Workflow filters for branches and tags have the keys only and ignore:
-
Any branches/tags that match
onlywill run the job. -
Any branches/tags that match
ignorewill not run the job. -
If neither
onlynorignoreare specified then the job is skipped for all branches/tags. -
If both
onlyandignoreare specified theonlyis considered beforeignore.
If both branch and tag filtering is configured and a push to your code includes both branch and tag information, the branch filters take precedence. In this scenario, if there are no branch filters configured, tag ignore filters are used, if they exist.
Branch-level job execution
The following example has one workflow that is configured to run different sets of jobs for different branches:
-
The
test_devjob is run on thedevbranch and any branch that beginsuser- -
The
test_stagejob is run on thestagebranch -
The
test_pre-prodjob is run on any branch startingpre-prodincluding any suffix added to the branch name using a hyphen.
Workflows ignore branches keys used in the jobs declaration. If you use the deprecated job-level branches key, replace them with workflow filters.
|
| This example shows how to provide strings and lists of strings when configuring workflow filters. |
workflows:
dev_stage_pre-prod:
jobs:
- test_dev:
filters: # using regex filters requires the entire branch to match
branches:
only: # only branches matching the below regex filters will run
- dev
- /user-.*/
- test_stage:
filters:
branches:
only: stage
- test_pre-prod:
filters:
branches:
only: /pre-prod(?:-.+)?$/
This setup can be illustrated as follows:
For more information on regular expressions, see the Using Regular Expressions to Filter Tags And Branches section below.
For a full example of workflows, see the configuration file for the Sample Sequential Workflow With Branching project.
Executing workflows for a git tag
| Webhook payloads are capped at 25 MB and for some events a maximum of 3 tags. If you push several tags at once, CircleCI may not receive them all. |
CircleCI does not run workflows for tags unless you explicitly specify tag filters using regular expressions. Both lightweight and annotated tags are supported.
If you have configured a job to run on a git tag you must also specify tag filters for any dependent jobs. Use regular expressions to specify tag filters for a job.
In the example below, two workflows are defined:
-
untagged-buildruns thebuildjob for all branches. -
tagged-buildrunsbuildfor all branches and all tags starting withv.
workflows:
untagged-build:
jobs:
- build
tagged-build:
jobs:
- build:
filters:
tags:
only: /^v.*/
In the example below, two jobs are configured within the build-deploy workflow:
-
The
buildjob runs for all branches and all tags. -
The
deployjob runs for all branches and only for tags starting with 'v'.
workflows:
build-deploy:
jobs:
- build:
filters: # required since `deploy` has tag filters AND requires `build`
tags:
only: /.*/
- deploy:
requires:
- build
filters:
tags:
only: /^v.*/
In the example below, three jobs are configured for the build-test-deploy workflow:
-
The
buildjob runs for all branches and only tags starting with 'config-test'. -
The
testjob runs once thebuildjob completes for all branches and only tags starting with 'config-test'. -
The
deployjob runs once thetestjob completes for no branches and only tags starting with 'config-test'.
workflows:
build-test-deploy:
jobs:
- build:
filters: # required since `test` has tag filters AND requires `build`
tags:
only: /^config-test.*/
- test:
requires:
- build
filters: # required since `deploy` has tag filters AND requires `test`
tags:
only: /^config-test.*/
- deploy:
requires:
- test
filters:
tags:
only: /^config-test.*/
branches:
ignore: /.*/
In the example below, two jobs are defined (test and deploy) and three workflows use those jobs:
-
The
buildworkflow runs for all branches exceptmainand is not run on tags. -
The
stagingworkflow will only run on themainbranch and is not run on tags. -
The
productionworkflow runs for no branches and only for tags starting withv..
workflows:
build: # This workflow will run on all branches except 'main' and will not run on tags
jobs:
- test:
filters:
branches:
ignore: main
staging: # This workflow will only run on 'main' and will not run on tags
jobs:
- test:
filters: &filters-staging # this yaml anchor is setting these values to "filters-staging"
branches:
only: main
- deploy:
requires:
- test
filters:
<<: *filters-staging # this is calling the previously set yaml anchor
production: # This workflow will only run on tags (specifically starting with 'v.') and will not run on branches
jobs:
- test:
filters: &filters-production # this yaml anchor is setting these values to "filters-production"
branches:
ignore: /.*/
tags:
only: /^v.*/
- deploy:
requires:
- test
filters:
<<: *filters-production # this is calling the previously set yaml anchor
Using regular expressions to filter tags and branches
CircleCI branch and tag filters support the Java variant of regex pattern matching. When writing filters, CircleCI matches exact regular expressions.
For example, only: /^config-test/ only matches the config-test tag. To match all tags starting with config-test, use only: /^config-test.*/ instead.
Using tags for semantic versioning is a common use case. To match patch versions 3-7 of a 2.1 release, you can write /^version-2\.1\.[3-7]/.
For full details on pattern-matching rules, see the java.util.regex documentation.
Using workspaces to share data between jobs
Each workflow has an associated workspace for transferring files to downstream jobs as a workflow progresses.
Configuration options are available to:
-
persist files to the workspace
- persist_to_workspace: root: /tmp/workspace paths: - target/application.jar - build/* -
attach a workflow’s workspace to a container.
- attach_workspace: at: /tmp/workspace
For further information on workspaces and their configuration see the Using Workspaces to Share Data Between Jobs doc.
Rerunning a workflow’s failed jobs
Workflows help to speed up your ability to respond to failures. One way to do this is to only rerun failed jobs rather than a whole workflow.
The steps detailed in this section show how to manually rerun only a workflow’s failed jobs. You can also set up automatic reruns for failed jobs. For more information, see the Automatic Reruns page.
To rerun only a workflow’s failed jobs, follow these steps:
-
In the CircleCI web app select your organization.
-
Select Pipelines in the sidebar.
-
Use the filters to find your project and pipeline.
-
Find the row in the pipeline view for the workflow you would like to rerun from failed and select the Rerun from failed icon. This option is also available in the workflow view using the rerun dropdown menu, which you can access by clicking on the workflow name or badge.
-
Rerun from the pipelines page
-
Rerun from the workflows page
| If you rerun a workflow containing a job that was previously re-run with SSH, the new workflow runs with SSH enabled for that job, even after SSH capability is disabled at the project level. |
Workflow states
The following state diagram shows the possible states and transitions of a workflow:
Workflows may have one of the following states:
| State | Description | Terminal state |
|---|---|---|
RUNNING |
Workflow is in progress |
No |
CANCELED |
Workflow canceled before it finished |
Yes |
FAILING |
A job in the workflow failed, but others are still running or yet to be approved |
No |
FAILED |
One or more jobs in the workflow failed |
Yes |
SUCCESS |
All jobs in the workflow completed successfully |
Yes |
NEEDS APPROVAL (UI) / ON HOLD |
A job in the workflow is waiting for approval |
No |
ERROR |
We experienced an internal error starting a job in the workflow |
Yes |
UNAUTHORIZED |
One or more of the jobs terminated with a |
Yes |
QUEUED |
The workflow is queued due to being part of a serial group. For more information, see the Controlling serial execution across your organization page. |
No |
| After 90 days non-terminal workflows are automatically cancelled by CircleCI. |
Troubleshooting
This section describes common problems and solutions for workflows.
Workflow and subsequent jobs do not trigger
If you do not see your workflows running, check for configuration errors that may be preventing the workflow from starting. Navigate to your project’s pipelines and find your workflow name to locate the failure.
Rerunning workflows fails
Failures may happen before a workflow runs during pipeline processing. Re-running the in this case workflow will fail. Push a change to the project repository or use the trigger pipeline option to rerun the pipeline.
| You cannot rerun jobs and workflows that are >= 90 days. |
Workflows waiting for status in GitHub
If you have workflows configured on a protected branch and the status check never completes, check the ci/circleci status key. ci/circleci is related to a deprecated check and should be and deselected.
Go to in GitHub and select Edit on the protected branch to deselect the settings, for example: https://github.com/your-org/project/settings/branches.
See also
-
See the workflows section of the FAQ.
-
For workflow configuration examples, see the CircleCI Demo Workflows page on GitHub.