Knowledgebase

Triggers and schedules in GitHub Actions, with every event in one table

What starts a workflow and how to say when. Triggers, activity types, filters, cron, and manual runs, then one table of every event GitHub fires, what fires by default, and what narrows it.

Nothing runs until something starts it. This page is the on block: the events, how to narrow them, the clock, the button, and a table of every event GitHub has.

⚡ Trigger

The events that start a run. No trigger, no run, ever.

  • Reach for it when you want a run at all. Every workflow names at least one event, and most name two or three.
  • Lives under on, at the top of the file: one event, a list of them, or a mapping that narrows each one.
on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

Gets you in trouble when

  • The file has no on. GitHub reads it, runs nothing, and only complains once you open that workflow in the Actions tab.
  • A pull_request comes from a fork. That run gets no secrets, on purpose, so a step that needs one fails there.
  • You switch to pull_request_target to get the secrets back. It runs your base branch's workflow with your token; check out the fork's code in it and the fork now holds your token.
  • You name the event and stop. Each one fires on its own default activities, rarely all of them; the next term says how to choose.

In the editor it is the When it runs panel: one card per trigger, Add a trigger for the catalogue, Turn off to drop one.

🎯 Activity types

Narrowing an event to the moments you care about: opened, closed, labeled.

  • Reach for it when an event fires more often than you want to pay for: an issue workflow that should run on labeled and nothing else.
  • Lives under the event as types, a list. Naming none is not all of them; each event has its own default set, and the table below has every one.
on:
  issues:
    types: [opened, labeled]
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]

Gets you in trouble when

  • You write no types on pull_request and expect a review to run it. Its default is opened, synchronize, reopened; the other eighteen wait to be named.
  • You name a type the event does not have. GitHub refuses the file, and the editor's findings say which one.
  • You pick edited on issues. Every saved change to a title or body fires it, which is more often than it sounds.

In the editor they are the Which activities? chips on a trigger card; a dot marks the ones GitHub picks when you pick none.

🔍 Filters

Narrowing further by branch, tag, or path.

  • Reach for it when a push to docs/ should not run the test suite, or only main should deploy.
  • Lives under push as branches, tags, and paths, under pull_request as branches and paths, each with an -ignore twin. workflow_run takes branches and workflows.
on:
  push:
    branches: [main, "release/**"]
    paths-ignore: ["**.md", "docs/**"]

Gets you in trouble when

  • You write branches and branches-ignore on the same event. GitHub takes one or the other; put a ! pattern in one list instead.
  • tags is filled in and branches is not. Only tag pushes run it then; an empty branch list is not every branch.
  • paths skips a pull request that touches nothing listed, and a required check waits on it forever. Run something small on those paths instead.
  • You put a filter on issues. It takes none; only the events with something in the last column of the table do.

In the editor each is a token field on the trigger card, Branches, Tags, Files changed; Only these or All but these picks which list it writes.

⏰ Cron

A five-field clock for running on a schedule.

  • Reach for it when nothing in GitHub marks the moment: a nightly build, a sweep every fifteen minutes.
  • Lives under schedule as a list of cron entries: minute, hour, day of month, month, day of week. Cron is UTC unless a timezone beside it says otherwise; your Tuesday 9am is not GitHub's.
on:
  schedule:
    - cron: "7-59/15 * * * *"
    - cron: "17 3 * * 1-5"
      timezone: Europe/London

Gets you in trouble when

  • The workflow is on a branch. A scheduled run only ever runs on the default branch, which surprises everyone once.
  • The minute is 0. Every cron on GitHub fires on the hour, the queue is longest there, and a run is delayed or dropped; pick an odd minute.
  • You reckon in local time. Cron is UTC, and it will not follow daylight saving with you.
  • The interval is under five minutes. Five is the shortest GitHub runs.
  • Nobody pushes for sixty days. GitHub switches the schedule off on a public repository, and the Actions tab has a button to switch it back on.

In the editor it is the On a timer card: Runs at holds the cron, read back in words beneath it, and every preset sits off the hour.

🖱️ Manual

Starting a run by hand, with inputs you declare.

  • Reach for it when a person should choose the moment: a deploy, a one-off sweep, or a workflow you are still writing.
  • Lives under workflow_dispatch, with inputs naming what the form asks: each a string, boolean, choice, number, or environment. A step reads one as inputs.name.
on:
  workflow_dispatch:
    inputs:
      environment:
        description: Where to deploy
        type: choice
        options: [staging, production]
        default: staging
      dry_run:
        description: Print what would change and stop
        type: boolean
        default: true

Gets you in trouble when

  • The Run workflow button is missing. GitHub shows it once the file is on the default branch; the branch picker on it then chooses what runs.
  • You start it with gh workflow run and skip a required input. The call is refused; give it a default, or pass it with -f.
  • You compare a boolean input with the text 'true'. It is a real boolean under inputs, so inputs.dry_run == 'true' is false whatever the box said; compare with true, or use it bare.

In the editor it is the Run it by hand card and its Inputs rows: name, what it is for, type, default, required. Start a run at the top dispatches the saved file with them.

📋 Event reference

Every event the editor's catalogue offers, in its order: what fires it, the activity types it fires by default and then the rest you can name, and the filters it takes.

The three retired classic project events are left out here, as the catalogue leaves them out.

Event, and what fires it Activity types, defaults first Filters
workflow_dispatch Someone presses Run workflow in the repository's Actions tab. none none
schedule Runs on a cron schedule, read in UTC. none none
workflow_call Another workflow calls this one and passes it inputs. none none
repository_dispatch Something outside GitHub posts an event to start this workflow. none none
issues An issue is opened, labelled, assigned, closed, or otherwise touched. All by default: opened, edited, deleted, transferred, pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, locked, unlocked, milestoned, demilestoned, typed, untyped, field_added, field_removed none
issue_comment A comment lands on an issue or on a pull request. All by default: created, edited, deleted none
discussion A discussion is opened, answered, or edited. All by default: created, edited, deleted, transferred, pinned, unpinned, labeled, unlabeled, locked, unlocked, category_changed, answered, unanswered none
discussion_comment A comment lands on a discussion. All by default: created, edited, deleted none
label A label is created, edited, or deleted in the repository. All by default: created, edited, deleted none
milestone A milestone is created, closed, edited, or deleted. All by default: created, closed, opened, edited, deleted none
pull_request A pull request is opened, gets new commits, or is closed. By default opened, synchronize, reopened. Also assigned, unassigned, labeled, unlabeled, edited, closed, converted_to_draft, ready_for_review, locked, unlocked, milestoned, demilestoned, review_requested, review_request_removed, auto_merge_enabled, auto_merge_disabled, enqueued, dequeued branches, branches-ignore, paths, paths-ignore
pull_request_review Someone approves, requests changes, or comments on the whole pull request. All by default: submitted, edited, dismissed none
pull_request_review_comment Someone comments on a line of a pull request's diff. All by default: created, edited, deleted none
pull_request_target Like a pull request, but running the base branch's code with its secrets. Never check out the fork's code here. By default opened, synchronize, reopened. Also assigned, unassigned, labeled, unlabeled, edited, closed, converted_to_draft, ready_for_review, locked, unlocked, review_requested, review_request_removed, auto_merge_enabled, auto_merge_disabled branches, branches-ignore, paths, paths-ignore
merge_group A group of pull requests is queued to merge together. All by default: checks_requested none
push Commits land on a branch or a tag. none branches, branches-ignore, tags, tags-ignore, paths, paths-ignore
create Someone creates a branch or a tag. none none
delete Someone deletes a branch or a tag. none none
gollum Someone creates or updates a page in the repository's wiki. none none
branch_protection_rule A branch protection rule is created, edited, or deleted. All by default: created, edited, deleted none
release A release is published, edited, or deleted. All by default: published, unpublished, created, edited, deleted, prereleased, released none
registry_package A package is published or updated in the registry. All by default: published, updated none
deployment Something creates a deployment. none none
deployment_status A deployment posts a new status. none none
page_build GitHub Pages rebuilds the site. none none
workflow_run A workflow you name is requested, starts, or completes. By default requested, completed. Also in_progress workflows, branches, branches-ignore
check_run One check is created, asked for again, or completes. All by default: created, rerequested, completed, requested_action none
check_suite A suite of checks is requested or completes. All by default: completed, requested, rerequested none
status A commit gets a new status from an integration. none none
fork Someone forks the repository. none none
watch Someone stars the repository. none none
public A private repository is made public. none none

In the editor the catalogue behind Add a trigger offers the same list in the same order, a star on the ones most workflows use.

📚 Straight from GitHub