How Do I Run a Workflow Manually?

Add a workflow_dispatch trigger with typed inputs, then start the run from the Actions tab or with one API call. Branch rules and a working example below.

Answer

Add a workflow_dispatch trigger to the workflow file, declare the inputs it needs with types, and the run starts either from the Run workflow button on the Actions tab or from a single API call. The trigger is documented on the events that trigger workflows reference (checked on 2026-08-13), and the one rule that catches most people is that the definition has to exist on the branch you run it from.

name: release
run-name: release ${{ inputs.version }} to ${{ inputs.environment }}

on:
  workflow_dispatch:
    inputs:
      environment:
        description: Target environment
        type: choice
        required: true
        default: staging
        options:
          - staging
          - production
      version:
        description: Tag to release, for example v2.4.1
        type: string
        required: true
      runner:
        description: Runner label for the build job
        type: choice
        required: true
        default: warp-ubuntu-latest-x64-8x
        options:
          - warp-ubuntu-latest-x64-4x
          - warp-ubuntu-latest-x64-8x
          - warp-ubuntu-latest-x64-16x
      dry_run:
        description: Build and test without publishing
        type: boolean
        default: true

jobs:
  build:
    runs-on: ${{ inputs.runner }}
    steps:
      - uses: actions/checkout@v5
        with:
          ref: ${{ inputs.version }}

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - run: npm ci
      - run: npm run build
      - run: npm test

  publish:
    needs: build
    if: ${{ !inputs.dry_run }}
    runs-on: warp-ubuntu-latest-x64-4x
    environment: ${{ inputs.environment }}
    steps:
      - uses: actions/checkout@v5
      - run: ./scripts/publish.sh ${{ inputs.version }}

Merge that to the default branch and the Actions tab shows a Run workflow button with a branch picker and one form field per input.

Detail

The five input types and how the two contexts differ

workflow_dispatch accepts up to 10 top level inputs, and each one declares a type. Every row below comes from the workflow syntax reference and the contexts reference, checked on 2026-08-13.

TypeForm controlinputs.<name> returnsgithub.event.inputs.<name> returns
stringText boxStringString
choiceDropdown built from optionsStringString
booleanCheckboxBoolean"true" or "false" as a string
numberText boxNumberString
environmentDropdown of repository environmentsStringString

That last column is the reason the example uses if: ${{ !inputs.dry_run }} rather than the github.event.inputs form. Under github.event.inputs, an unchecked box arrives as the string "false", which is truthy, so the publish job would run on every dispatch. Read booleans through the inputs context and the condition behaves the way the checkbox looks.

Two more constraints worth knowing before you design the form. A choice input needs an options list, and its default has to be one of those options or the run fails validation. Inputs marked required: true block the form until they are filled, while the API rejects the call outright when one is missing.

Starting the run from the API

The REST endpoint takes the workflow file name in the path and the branch or tag in the body (workflows REST API, checked on 2026-08-13):

curl -X POST \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $GH_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/OWNER/REPO/actions/workflows/release.yml/dispatches \
  -d '{"ref":"main","inputs":{"environment":"production","version":"v2.4.1","runner":"warp-ubuntu-latest-x64-16x","dry_run":"false"}}'

Four practical notes. The token needs Actions write access. Input values travel as strings and GitHub coerces them to the declared type. A successful call returns 204 No Content and no run id, so the run has to be located afterwards. And a dispatch sent with the built in GITHUB_TOKEN does create a run, because workflow_dispatch and repository_dispatch are the two exceptions to the recursion guard described in the automatic token authentication documentation.

The same call from the GitHub CLI, which is easier to keep in a release script:

gh workflow run release.yml --ref main \
  -f environment=production \
  -f version=v2.4.1 \
  -f runner=warp-ubuntu-latest-x64-16x \
  -f dry_run=false

gh run list --workflow release.yml --event workflow_dispatch \
  --branch main --limit 1 --json databaseId,displayTitle,status

The run-name line in the workflow is what makes that second command useful. Each dispatch gets a title containing its inputs, so the list distinguishes a staging dry run from a production release without opening either.

The branch rule

The trigger has to exist in the workflow file on the ref you are dispatching, and the Actions tab reads its workflow list from the default branch (events that trigger workflows reference, checked on 2026-08-13). Three consequences follow.

  • A workflow_dispatch trigger that lives only on a feature branch produces no Run workflow button anywhere. Merge it to the default branch first.
  • Once the button exists, the branch dropdown covers any branch or tag, and the run executes that ref's copy of the file. Editing steps on a branch changes what a dispatch of that branch does.
  • Dispatching a ref whose copy of the file has no workflow_dispatch trigger returns HTTP 422 with the message that the workflow does not have a workflow_dispatch trigger (workflows REST API). The fix is a merge, not a retry.

The workflow_dispatch glossary entry covers the event itself, and running jobs on a schedule covers the schedule trigger, which carries the same default branch rule.

What a manual run costs

Manual runs are usually the long ones: releases, migrations, load tests, full matrix reruns. Making the runner label an input prices them one dispatch at a time, since the same workflow can take a small machine for a routine release and a large one when a fix is waiting. Rates below come from the cloud runners catalog and the pricing page, and the GitHub rate from the GitHub Actions billing reference, all checked on 2026-08-13.

Label chosen at dispatch timeShapePer minute20 minute release run12 runs a month
warp-ubuntu-latest-x64-4x4 vCPU, 16 GB$0.008$0.16$1.92
warp-ubuntu-latest-x64-8x8 vCPU, 32 GB$0.016$0.32$3.84
warp-ubuntu-latest-x64-16x16 vCPU, 64 GB$0.032$0.64$7.68
the 8-core Linux larger runner, GitHub-hosted8 vCPU, 32 GB$0.022$0.44$5.28

At the 8 vCPU shape, warp-ubuntu-latest-x64-8x costs $0.016 per minute against $0.022 per minute for the 8-core Linux larger runner: 27 percent lower list price, GitHub list price checked on 2026-08-13.

A manual release that builds a Mac artifact and a Linux artifact can put both labels in the same dispatch form. Setup is the account, the GitHub bot from the dashboard, and the label (quick start documentation).

Why is the Run workflow button missing from the Actions tab?

The workflow file carrying the trigger is not on the default branch. GitHub builds the Actions tab list from the default branch (events that trigger workflows reference), so a workflow_dispatch block added on a feature branch stays invisible until it merges. After the merge, the branch dropdown on the button lets you dispatch the feature branch and run that branch's version of the file.

Can I start a run from a script or another workflow?

Yes. POST to /repos/OWNER/REPO/actions/workflows/release.yml/dispatches with a ref and an inputs object, using a token with Actions write access (workflows REST API). The WarpBuild automation API exposes runner-image and custom-runner operations, so a script can prepare the runner and then dispatch the workflow that exercises it (automation documentation).

Can a manual run choose its own runner size?

Yes. Declare a choice input listing the labels you allow and set runs-on to that input, as in the example above. The dropdown becomes the size control, which keeps a routine release on warp-ubuntu-latest-x64-4x at $0.008 per minute and lets a release under time pressure take warp-ubuntu-latest-x64-16x at $0.032 per minute (pricing page, checked on 2026-08-13). More ways to shorten those runs are in speeding up GitHub Actions.

How do I find the run the API just started?

The dispatch response is 204 No Content with no body, so nothing comes back to poll on directly. Put the inputs into run-name, then list runs filtered by event=workflow_dispatch and the branch you dispatched and take the newest databaseId (workflow runs REST API). Scheduled equivalents of the same job are covered in nightly builds in GitHub Actions.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.