GitLab CI pipelines can be triggered on a schedule, but the schedules are actually defined by cron syntax, not a simple "every X minutes" setting.

Let’s see a pipeline in action. Imagine you have a gitlab-ci.yml file like this:

stages:
  - build
  - deploy

build_app:
  stage: build
  script:
    - echo "Building the application..."
    - echo "Build successful!"

deploy_staging:
  stage: deploy
  script:
    - echo "Deploying to staging..."
    - echo "Deployment to staging complete!"
  only:
    - schedules

Notice the only: - schedules line. This is crucial. It tells GitLab CI that this particular job should only run when triggered by a scheduled pipeline.

Now, to set up the schedule itself, you’d navigate to your GitLab project. Go to CI/CD -> Schedules. You’ll see a list of existing schedules and an "Add schedule" button.

Clicking "Add schedule" brings you to a form. You’ll define:

  • Description: A human-readable name for your schedule (e.g., "Daily staging deploy").
  • Target Branch: The branch this scheduled pipeline will run against (e.g., main or master).
  • Cron Syntax: This is where the magic happens. You’ll enter a cron expression to define when the pipeline should run.

Let’s break down some common cron examples for GitLab CI schedules:

  • Run every day at 3:00 AM:

    0 3 * * *
    

    This means: 0 minutes, 3 hours, any day of the month, any month, any day of the week.

  • Run every Monday at 9:00 PM:

    0 21 * * 1
    

    Here, 1 represents Monday (Sunday is 0 or 7).

  • Run every 15 minutes:

    */15 * * * *
    

    The */15 means "every 15 minutes."

  • Run on the 1st and 15th of every month at midnight:

    0 0 1,15 * *
    

    The 1,15 specifies the days of the month.

  • Run every hour on weekdays (Monday-Friday) at the top of the hour:

    0 * * * 1-5
    

Once you’ve entered your cron syntax and saved the schedule, GitLab will automatically trigger a pipeline on the specified target branch at the defined times. The deploy_staging job in our example will then execute because it’s configured to run for schedules.

The core problem this solves is automating repetitive tasks. Instead of manually clicking "Run pipeline" for your nightly builds, deployments, or cleanup scripts, you can set them and forget them. GitLab handles the timing, ensuring your code is tested, deployed, or maintained at predictable intervals.

The system uses a background worker process that periodically checks the defined cron schedules against the current time. When a match is found, it creates a new pipeline for the specified branch and assigns it the schedule tag. Jobs with only: [schedules] (or rules: if: '$CI_PIPELINE_SOURCE == "schedule"') then pick up this pipeline.

A common point of confusion is that GitLab CI schedules are not timezone-aware by default. The cron times are interpreted relative to the timezone configured on your GitLab server. If your server is in UTC, your "3:00 AM" schedule will run at 3:00 AM UTC, not necessarily 3:00 AM local time for your team. To manage this, you can either set your server’s timezone appropriately or use a cron syntax that accounts for the offset. For instance, if your server is UTC and you want a schedule to run at 3:00 AM PST (UTC-8), you’d set the cron to 0 11 * * * (3 AM + 8 hours).

The next concept you’ll likely explore is using variables within your scheduled pipelines, especially to manage environment-specific configurations or secrets that should only be accessed by scheduled jobs.

Want structured learning?

Take the full Gitlab course →