You can schedule CircleCI pipelines to run on a cron schedule by defining a cron schedule in your .circleci/config.yml file.

Here’s a simple pipeline that runs every hour:

version: 2.1

jobs:
  build:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run: echo "Running on $(date)"

workflows:
  build-workflow:
    jobs:
      - build:
          filters:
            branches:
              ignore:
                - main # Don't run cron on the main branch directly
          triggers:
            - schedule:
                cron: "0 * * * *" # Run every hour
                filters:
                  branches:
                    only:
                      - main # Only trigger on the main branch

This configuration tells CircleCI to execute the build job every hour. The cron syntax used here is standard cron format, where:

  • The first * represents minutes (0-59).
  • The second * represents hours (0-23).
  • The third * represents days of the month (1-31).
  • The fourth * represents months (1-12).
  • The fifth * represents days of the week (0-6, where 0 is Sunday).

So, "0 * * * *" means "at minute 0 of every hour, every day of the month, every month, every day of the week."

The filters are crucial here. We’re ignoring the main branch for general triggers (branches: ignore: - main) to prevent accidental manual runs or other non-cron triggers from affecting the main branch directly if that’s not desired. However, within the schedule trigger itself, we specify branches: only: - main. This ensures that this specific cron schedule only applies when the main branch is the target. If you wanted this cron job to run on a develop branch, you’d change only: - main to only: - develop.

How it Works Internally

CircleCI’s scheduler is a separate internal service. When you define a schedule trigger with a cron expression, CircleCI registers this request. The scheduler then periodically checks its list of scheduled jobs. When the time matches your cron expression for a given repository and branch, it initiates a new pipeline run, effectively triggering a commit to that branch with a special metadata tag indicating it was a scheduled run. This is why the filters on branches are important – they tell the scheduler which branch to target when it’s time to run.

Controlling the Schedule

You can define multiple schedule triggers for the same job or different jobs within a workflow. For example, to run a job daily at midnight and another job weekly on Sunday at 9 AM:

version: 2.1

jobs:
  daily_report:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run: echo "Generating daily report..."

  weekly_summary:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run: echo "Generating weekly summary..."

workflows:
  main-workflow:
    jobs:
      - daily_report:
          filters:
            branches:
              only:
                - main
          triggers:
            - schedule:
                cron: "0 0 * * *" # Daily at midnight
                filters:
                  branches:
                    only:
                      - main
      - weekly_summary:
          filters:
            branches:
              only:
                - main
          triggers:
            - schedule:
                cron: "0 9 * * 0" # Weekly on Sunday at 9 AM
                filters:
                  branches:
                    only:
                      - main

Important Considerations and Nuances

The cron syntax in CircleCI is slightly different from standard Unix cron in that it does not support the * * * * * pattern for "every minute." You must specify at least one number. If you want to run something very frequently, like every 5 minutes, you’d use "*/5 * * * *".

The most surprising thing about CircleCI’s cron scheduling is that it doesn’t actually run on your code. Instead, when a scheduled time hits, CircleCI creates a new commit on the specified branch with a special marker. This means your pipeline is triggered by a commit, just like a regular push, but it’s a synthetic commit generated by CircleCI itself. This has implications for how you might track changes or trigger other systems that react to Git commits. If your pipeline logic relies on diffs or specific commit messages, you’ll need to account for this synthetic commit.

You can also use CircleCI’s UI to manage schedules. Navigate to your project on CircleCI, go to "Workflows," then "Schedules." Here, you can create, edit, and delete schedules, and set branch filters and cron expressions without directly modifying your config.yml. This is often a cleaner way to manage schedules, especially if multiple people are contributing to the CI configuration.

The filters section within the schedule trigger is powerful. You can specify branches to only run on certain branches, or tags to only run when a tag matching a pattern is pushed (though typically cron is branch-focused). If you omit the filters within the schedule trigger, it will attempt to run on all branches, which is rarely what you want.

The next concept you’ll likely encounter is handling the output of these scheduled jobs, perhaps aggregating them into reports or sending notifications based on their success or failure.

Want structured learning?

Take the full Circleci course →