GitLab CI pipelines can be scheduled to run automatically at specific times using cron syntax.
Let’s see this in action. Imagine you have a nightly build that needs to run every day at 2 AM. You’d add this to your .gitlab-ci.yml file:
stages:
- build
- test
nightly_build:
stage: build
script:
- echo "Running nightly build..."
- ./build_script.sh
cron: "0 2 * * *" # This runs daily at 2:00 AM
Here, cron: "0 2 * * *" is the key. It uses standard cron syntax:
0: Minute (0-59). Here, the 0 means at the start of the hour.2: Hour (0-23). Here, 2 means 2 AM.*: Day of the month (1-31). The asterisk means "every day of the month."*: Month (1-12). The asterisk means "every month."*: Day of the week (0-6, Sunday=0 or 7). The asterisk means "every day of the week."
So, 0 2 * * * translates to "at minute 0 of hour 2, on every day of the month, in every month, on every day of the week."
This feature is incredibly useful for automating routine tasks that don’t necessarily need to be triggered by code changes. Think about:
- Nightly builds: Compiling your code, running integration tests, and creating artifacts.
- Scheduled reports: Generating performance reports, security scans, or usage statistics.
- Data synchronization: Updating external services or databases with the latest information.
- Cleanup tasks: Removing old artifacts, temporary files, or expired data.
When a cron job is triggered, GitLab creates a pipeline. By default, this pipeline runs on the master (or main) branch. You can specify a different branch if needed. The pipeline will also have a specific variable, CI_PIPELINE_SOURCE, set to schedule.
Let’s say you want to run a deployment job only on weekends. You can use a slightly different cron schedule:
stages:
- deploy
deploy_to_staging_weekend:
stage: deploy
script:
- echo "Deploying to staging..."
- ./deploy_script.sh staging
cron: "30 3 * * 6" # This runs every Saturday at 3:30 AM
Here, 30 3 * * 6 means:
30: At minute 30.3: At hour 3 (3 AM).*: On every day of the month.*: In every month.6: On day 6 of the week (Saturday, assuming Sunday is 0).
This allows you to have granular control over when your automated tasks execute.
You can manage these scheduled pipelines directly within the GitLab UI. Navigate to your project’s CI/CD > Schedules page. Here you can create, edit, disable, or delete scheduled pipelines. You can also see the last run time and the status of each schedule. When you create a schedule via the UI, you’ll be prompted to select a branch and define the cron interval.
A common pattern is to use a scheduled pipeline to trigger other pipelines, perhaps with different parameters or on different projects. For instance, a "master" schedule might run at midnight, and its script could execute gitlab-runner exec docker trigger-pipeline --project my-other-project --branch main --token <your-trigger-token>.
The cron syntax itself is quite flexible. For example, to run a pipeline every 15 minutes, you could use */15 * * * *. To run it twice a day, say at 9 AM and 5 PM, you might use 0 9,17 * * *. GitLab’s UI provides a helpful validator to ensure your cron expression is syntactically correct.
It’s important to understand that the cron schedule in GitLab CI is evaluated by the GitLab server itself, not by the runners. When the scheduled time arrives, GitLab initiates a pipeline on the specified branch. The runner then picks up this pipeline just like any other pipeline triggered by a commit. This means the availability of runners doesn’t affect when the schedule is considered, only when the job actually starts executing.
If you have a job that you want to run on a schedule but only if it’s not already running from a manual or code-triggered pipeline, you can add a condition using the CI_PIPELINE_SOURCE variable. For example:
stages:
- cleanup
cleanup_old_data:
stage: cleanup
script:
- echo "Cleaning up old data..."
- ./cleanup_script.sh
cron: "0 1 * * *" # Daily at 1 AM
only:
variables:
- CI_PIPELINE_SOURCE == "schedule"
This only clause ensures that the cleanup_old_data job will only execute if the pipeline was initiated by a schedule. If someone manually triggers a pipeline or a commit pushes a new pipeline, this specific job won’t run.
When a cron job runs, it creates a pipeline that is associated with the branch specified in the schedule configuration. This means that the pipeline’s commit SHA will be the latest commit on that branch at the time the schedule is triggered. If the branch has moved forward since the last scheduled run, the new pipeline will be based on the most recent commit.
The primary lever you control is the cron expression itself, dictating the frequency and timing. Beyond that, you manage which jobs are included in the scheduled pipeline, what scripts they execute, and on which branch the pipeline should run. The only and except keywords, along with the variables condition as shown above, provide further control over job execution within scheduled pipelines.
The next step after mastering cron schedules is often exploring conditional pipeline execution based on external triggers or variables.