GitHub Actions Scheduled Workflows — cron Syntax and Examples
Schedule GitHub Actions workflows with cron expressions using the schedule trigger. Learn the cron syntax, timezone behavior (UTC only), avoiding missed runs, and examples for...
GitHub Actions schedule trigger uses standard cron syntax but runs in UTC only. Workflows can miss their scheduled time during high load — design them to be idempotent.
Build cron expressions with the Cron Builder.
Basic schedule trigger
# .github/workflows/nightly.yml
name: Nightly Build
on:
schedule:
- cron: '0 2 * * *' # 2:00 AM UTC every day
workflow_dispatch: # Allow manual trigger
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run nightly build
run: npm ci && npm run build
Important: Always add workflow_dispatch alongside schedule so you can test and trigger manually.
Cron syntax for GitHub Actions
# Format: minute hour day-of-month month day-of-week
# 0-59 0-23 1-31 1-12 0-6 (0=Sun)
on:
schedule:
# Every hour:
- cron: '0 * * * *'
# Every day at midnight UTC:
- cron: '0 0 * * *'
# Every Monday at 9 AM UTC:
- cron: '0 9 * * 1'
# First day of every month at 6 AM:
- cron: '0 6 1 * *'
# Every 15 minutes:
- cron: '*/15 * * * *'
# Weekdays at 8 AM UTC (Mon-Fri):
- cron: '0 8 * * 1-5'
Note: GitHub Actions minimum schedule interval is 5 minutes.
Multiple schedules
on:
schedule:
- cron: '0 8 * * 1-5' # Weekday morning run
- cron: '0 0 * * 0' # Sunday midnight cleanup
Timezone handling (UTC only)
GitHub Actions schedule only supports UTC. To convert:
# If your team is in Eastern time (UTC-5 or UTC-4 with DST):
# "9 AM New York" = 14:00 UTC (EST) or 13:00 UTC (EDT)
# Use 14:00 UTC to be consistent with EST, or accept 1-hour shift in summer:
on:
schedule:
- cron: '0 14 * * 1-5' # Roughly 9 AM ET (EST)
For precise timezone-aware scheduling, use GitHub Actions Cron with environment variables or use a separate scheduler like AWS EventBridge.
Common scheduled workflow patterns
Dependency updates check
name: Dependency Audit
on:
schedule:
- cron: '0 6 * * 1' # Every Monday at 6 AM UTC
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm audit --audit-level=high
- name: Check for outdated packages
run: npx npm-check-updates --errorLevel 2
Database backup
name: Database Backup
on:
schedule:
- cron: '0 1 * * *' # Daily at 1 AM UTC
jobs:
backup:
runs-on: ubuntu-latest
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
steps:
- name: Create backup
run: |
pg_dump $DATABASE_URL | gzip > backup-$(date +%Y%m%d).sql.gz
- name: Upload to S3
run: |
aws s3 cp backup-*.sql.gz s3://my-backups/db/ \
--storage-class STANDARD_IA
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Weekly report
name: Weekly Report
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9 AM UTC
workflow_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate report
run: node scripts/generate-report.js
- name: Send to Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Weekly report ready: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Check if run was triggered by schedule
steps:
- name: Different behavior for scheduled vs manual
run: |
if [ "${{ github.event_name }}" == "schedule" ]; then
echo "Running scheduled job with extra cleanup"
npm run scheduled-cleanup
else
echo "Manual trigger"
fi
Prevent concurrent runs
name: Scheduled Job
on:
schedule:
- cron: '0 * * * *'
concurrency:
group: scheduled-job
cancel-in-progress: false # Don't cancel — wait for previous to finish
Related tools
- Cron Builder — build and validate cron expressions
- Timestamp Converter — convert UTC times
- Hash Generator — generate cache-busting hashes for builds
Related posts
- Cron Expression Syntax, Explained by Field — Five fields, nine special characters, a dozen edge cases. A complete reference f…
- Cron Pitfalls: Timezones, DST, and Missed Runs — Your cron job will run twice or skip entirely when DST changes. Here's why, how …
- AWS EventBridge Scheduler — Cron Schedules for Lambda and AWS Services — AWS EventBridge Scheduler runs Lambda functions, ECS tasks, and other AWS target…
- Cron Expression Guide — Syntax, Fields, and Special Characters — Cron expressions schedule recurring jobs using five or six fields: minute, hour,…
- Cron Job Scheduling — How Cron Works and Best Practices — Cron runs scheduled tasks using 5-field time expressions. Learn how cron daemons…
Related tool
Build and parse cron expressions with human-readable explanations.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.