Skip to content

Manual Triggers and Inputs


A plain workflow_dispatch button is useful, but a button with fields next to it is where manual triggers actually start pulling their weight. Instead of a workflow that always does the same fixed thing, inputs let the person clicking “Run workflow” decide things at run time — which environment to deploy to, whether to skip tests, what version to roll back to. This is what turns a static automation script into an actual tool.

Defining Inputs

Inputs are declared under workflow_dispatch.inputs, each with a type, an optional description, a default, and whether it’s required.

name: Manual Inputs Demo
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Target environment'
        type: choice
        options:
          - staging
          - production
        default: staging
      skip-tests:
        description: 'Skip the test suite'
        type: boolean
        default: false
      release-notes:
        description: 'Short release note'
        type: string
        required: false

jobs:
  announce:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "Deploying to: ${{ inputs.environment }}"
          echo "Skip tests: ${{ inputs.skip-tests }}"
          echo "Notes: ${{ inputs.release-notes }}"

Let’s take a small portion to learn to read:

...
    inputs:
      environment:
        description: 'Target environment'
        type: choice
        options:
          - staging
          - production
        default: staging
  • The input is given environment as it’s uniquie identifier (give it any).
  • environment accepts inputs of type (kind of data type) choice where user will be provided two options to choose from namely staging and prodduction while defaulting to staging.
  • description is just a description for reference or to understand what this input is for.

Set it up:

mkdir gha-inputs-demo && cd gha-inputs-demo
git init
mkdir -p .github/workflows
cat > .github/workflows/manual-inputs.yml << 'EOF'
name: Manual Inputs Demo
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Target environment'
        type: choice
        options:
          - staging
          - production
        default: staging
      skip-tests:
        description: 'Skip the test suite'
        type: boolean
        default: false
      release-notes:
        description: 'Short release note'
        type: string
        required: false

jobs:
  announce:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "Deploying to: ${{ inputs.environment }}"
          echo "Skip tests: ${{ inputs.skip-tests }}"
          echo "Notes: ${{ inputs.release-notes }}"
EOF
git add .
git commit -m "Add manual inputs demo workflow"
git branch -M main

Push this to GitHub and open the “Run workflow” panel — instead of a bare button, you’ll now see a dropdown for environment, a checkbox for skip-tests, and a free-text box for release-notes. This UI is generated entirely from the YAML; you never touch anything but the workflow file to define it.

Input Types

TypeUI ElementNotes
stringText boxDefault type if omitted
booleanCheckboxAccessed as true/false string in expressions
choiceDropdownRequires an options list; value is always one of those strings
environmentDropdown of configured GitHub EnvironmentsTies into environment protection rules and secrets

Note

Even boolean and choice inputs are passed through as strings when the workflow actually runs — there’s no true boolean type at execution time. ${{ inputs.skip-tests }} evaluates to the literal string "true" or "false", which matters if you’re doing strict comparisons later.

Using Inputs In Conditionals

Inputs become genuinely useful once they control workflow behavior, not just get echoed.

jobs:
  test:
    if: ${{ inputs.skip-tests == false }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "Running tests..."

  deploy:
    needs: test
    if: ${{ always() && !failure() }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to ${{ inputs.environment }}"

This job-level if skips the entire test job when the checkbox is ticked. The full mechanics of if: conditionals and expressions get their own dedicated treatment shortly — for now, notice how naturally an input flows straight into a decision about what runs. Don’t try yet because it might confuse you, we will look into if after few chapters.

Required Inputs

Marking an input required: true without a default forces the person triggering the workflow to supply a value before it can run — the “Run workflow” button stays disabled until every required field is filled.

inputs:
  version:
    description: 'Version to roll back to'
    type: string
    required: true

Use this for anything genuinely dangerous to leave blank — a rollback target, a destructive cleanup scope — where a silently-applied default could cause real damage.

Triggering With Inputs From The CLI

The GitHub UI isn’t the only way to fire workflow_dispatch. The gh CLI and the REST API can trigger it too, passing inputs as key-value pairs — this is how other automation (a chatbot, a separate pipeline, a cron job outside GitHub) can kick off a workflow programmatically.

gh workflow run manual-inputs.yml \
  -f environment=production \
  -f skip-tests=false \
  -f release-notes="Hotfix for login bug"

This requires the gh CLI to be authenticated against your repository — install and log in with gh auth login if you haven’t already.

How Real DevOps Engineers Use This

Manual-trigger inputs are the backbone of self-service deploy tooling. Instead of engineers running deploy scripts from their laptop with locally-stored AWS credentials, teams expose a workflow_dispatch workflow with an environment choice input and a version string input, restrict who can trigger it using repository permissions, and let people deploy through a controlled, logged, auditable UI instead of an SSH session. Every run shows up in the Actions history with exactly who triggered it and what values they chose — which is a meaningfully better audit trail than “someone ran a script somewhere.”

The environment input type specifically is worth calling out: when it’s tied to a configured GitHub Environment (not just a choice dropdown of the string “production”), it can enforce required reviewers before a job proceeds — meaning a workflow_dispatch targeting production can require a second person to approve the run before it executes. That’s a real safety mechanism, not just cosmetic.

Clean up:

cd .. && rm -rf gha-inputs-demo

Tip

If you find yourself duplicating almost-identical workflows for staging and production, inputs are usually the fix — one workflow, one environment choice input, and conditionals or an input-driven variable deciding the target instead of two nearly-copy-pasted files.

Last updated on