GitHub Actions Inputs Explained | Workflow Inputs, Reusable Workflows & Production Use Cases
Modern CI/CD pipelines rarely operate on static, hardcoded values. Enterprise pipelines must dynamically support multiple environments (e.g., dev, QA, pre-prod, prod), diverse deployment strategies, and distinct microservice configurations at runtime. This chapter covers GitHub Actions Inputs, demonstrating how to pass runtime data into workflows, centralize deployment logic across teams using reusable workflows, and establish environment-aware automation.
1. The Need for Dynamic CI/CD Pipelines
In simple automation setups, workflow steps execute based entirely on hardcoded steps and fixed configurations. However, production software delivery demands flexibility:
- Multi-Environment Delivery: A single pipeline must be capable of deploying to
dev,QA,pre-prod, orprodbased on operational needs. - Granular Task Execution: Certain tasks (like deep vulnerability scanning or full integration test suites) may be mandatory for
QAorprodbut unnecessary for fastdeviterations. - Standardization across Services: Organizations managing dozens or hundreds of microservices require standard deployment pipelines without duplicating pipeline logic across every repository.
To handle dynamic execution without writing dozens of repetitive, single-purpose workflow files, GitHub Actions provides Inputs—a mechanism to supply user-defined or caller-defined parameters to pipelines at runtime.
2. Core Taxonomy: The Three Types of Inputs
GitHub Actions categorizes inputs into three distinct structural patterns depending on where parameters originate and where they are consumed.
3. Workflow Inputs & Manual Triggering Mechanisms
Workflow inputs allow human operators, external webhooks, or automation scripts to supply parameters when manually triggering a workflow via the workflow_dispatch event.
Triggering Workflow Dispatch Beyond the UI
While engineers frequently click the "Run workflow" button in the GitHub web interface, manual execution is not restricted to the UI console.
Real-Life Analogy
Creating an AWS EC2 instance can be done through the AWS Management Console UI, via the
aws ec2 run-instancesCLI, or programmatically via Terraform. Under the hood, all three methods issue HTTPS requests to the exact same underlying AWS EC2 API.Similarly, triggering a
workflow_dispatchexecution can be initiated via:
- GitHub Web Console (UI button)
- GitHub CLI (
gh): Executing terminal commands directly.- GitHub REST API: Automated API calls from external orchestrators.
GitHub CLI (gh) Example:
gh workflow run "01-workflow-inputs-demo.yml" \
-f environment="prod" \
-f perform_smoke_test="true"
4. Workflow Input Data Types & Mental Models
When declaring workflow inputs under on.workflow_dispatch.inputs, GitHub Actions supports multiple data types to validate and structure user input.
Production Best Practice: choice vs. string
Rule of Thumb: Prefer
choiceoverstringwhenever the acceptable set of parameters is known ahead of time. Freeform text fields (string) introduce human typographical errors (e.g., typingprdoinstead ofprod). Dropdowns enforce deterministic pipelines.
YAML Schema Syntax Example
on:
workflow_dispatch:
inputs:
environment:
description: "Select the target deployment environment"
required: true
default: "dev"
type: choice
options:
- dev
- QA
- prod
perform_smoke_test:
description: "Execute automated post-deployment smoke tests"
required: true
default: false
type: boolean
5. Data vs. Logic: Inputs vs. Expressions and Functions
A common point of confusion for pipeline engineers is the distinction between inputs, expressions, and context objects.
- Inputs (
${{ inputs.<input_name> }}): The raw data supplied to the workflow at runtime (e.g.,"prod"ortrue). - Expressions & Functions (
if: ${{ ... }}): The logic engine that evaluates the raw input data and decides what action to take.
# Step execution governed by input evaluation
- name: Deploy to Kubernetes
if: ${{ inputs.environment == 'prod' }}
run: echo "Executing production deployment manifest..."
6. Walkthrough: Building an Environment-Aware CI Pipeline
To illustrate workflow inputs, we will examine a complete pipeline for a Python Flask application that dynamically alters its build, scanning, registry push, and deployment steps based on user choices.
Project Context
The sample application (app.py) exposes a Flask web server listening on port 5000:
from flask import Flask, jsonify
import os
app = Flask(__name__)
@app.route("/")
def home():
return "Welcome to Cloud with Varun Joshi GitHub Actions Docker + Flask!"
@app.route("/health")
def health():
return jsonify({"status": "healthy"}), 200
if __name__ == "__main__":
port = int(os.environ.get("PORT", 5000))
app.run(host="0.0.0.0", port=port)
And its companion Dockerfile:
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
Complete Environment-Aware Workflow Definition
Path: .github/workflows/01-workflow-inputs-demo.yml
name: "01 - Workflow Inputs Demo"
on:
workflow_dispatch:
inputs:
environment:
description: "Target Deployment Environment"
required: true
default: "dev"
type: choice
options:
- dev
- QA
- prod
perform_smoke_test:
description: "Run automated health/smoke checks"
required: true
type: boolean
default: false
env:
APP_NAME: "cwvj-flask-app"
DOCKER_USER: "cloudwithvarjosh"
IMAGE_TAG: "v1.0.1"
jobs:
flask-ci-job:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Display Input Parameters
run: |
echo "Selected Environment: ${{ inputs.environment }}"
echo "Execute Smoke Test: ${{ inputs.perform_smoke_test }}"
- name: Build Docker Image
uses: docker/build-push-action@v5
with:
context: .
push: false
tags: ${{ env.DOCKER_USER }}/${{ env.APP_NAME }}:${{ env.IMAGE_TAG }}
- name: QA Vulnerability & Compliance Scan
if: ${{ inputs.environment == 'QA' }}
run: echo "Running automated vulnerability scan for QA validation..."
- name: Login to Docker Hub
if: ${{ inputs.environment != 'dev' }}
uses: docker/login-action@v3
with:
username: ${{ env.DOCKER_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Push Container Image to Registry
if: ${{ inputs.environment != 'dev' }}
run: echo "Pushing image ${{ env.DOCKER_USER }}/${{ env.APP_NAME }}:${{ env.IMAGE_TAG }} to Docker Hub..."
- name: Run Local Test Container
run: |
docker run -d -p 5000:5000 --name flask-app ${{ env.DOCKER_USER }}/${{ env.APP_NAME }}:${{ env.IMAGE_TAG }}
sleep 3
- name: Execute Smoke Tests
if: ${{ inputs.perform_smoke_test == true }}
run: |
echo "Hitting /health endpoint..."
curl -f http://localhost:5000/health
- name: Deploy to Kubernetes Cluster
if: ${{ inputs.environment == 'prod' }}
run: echo "Applying Production Kubernetes Manifests..."
Operational Pipeline Behavior Breakdown
Production Design Note: In dev environments, images are built and validated locally on the runner without pushing to Docker Hub. This prevents unverified developer commits from polluting container registries with transient image tags.
7. Real-World Production Pattern: Reusable Workflows
The 50-Microservice Scaling Problem
In an enterprise GitHub Organization containing 50 distinct microservices across 50 repositories, maintaining identical deployment pipelines in every repository creates mass operational overhead. If security compliance mandates a change in the container scanning process, developers must manually update 50 individual .github/workflows/deploy.yml files.
Real-Life Analogy
In Jenkins, engineers centralize repetitive pipeline logic into Jenkins Shared Libraries. Pipeline scripts simply import the shared library and supply microservice-specific parameters.
GitHub Reusable Workflows serve the exact same architecture in GitHub Actions. Common operational workflows (building, scanning, deploying) are defined once in a centralized location, and microservice repositories invoke them while passing dynamic runtime inputs.
8. Architecture of Reusable Workflows (workflow_call)
Reusable workflows utilize the workflow_call trigger to declare required parameters. Calling workflows invoke reusable workflows using the jobs.<job_id>.uses syntax and provide values via the with: block.
Comparison: Reusable vs. Calling Workflow Constructs
9. Walkthrough: Standardized Microservice Deployment
Below is a complete enterprise implementation demonstrating how a calling pipeline executes local microservice steps (unit testing, building artifacts) before delegating deployment to a centralized reusable workflow.
1. Centralized Reusable Workflow
Path: .github/workflows/deploy.yml
name: "Reusable Deployment Workflow"
on:
workflow_call:
inputs:
application_name:
description: "Name of the service being deployed"
required: true
type: string
run_security_scans:
description: "Flag to enforce automated security scans"
required: true
type: boolean
replicas:
description: "Target Kubernetes replica scale count"
required: true
type: number
jobs:
deploy-application-job:
runs-on: ubuntu-latest
steps:
- name: Display Deployment Parameters
run: |
echo "Deploying Application: ${{ inputs.application_name }}"
echo "Configured Replicas: ${{ inputs.replicas }}"
echo "Security Scanning Enabled: ${{ inputs.run_security_scans }}"
- name: Execute Security Validation
if: ${{ inputs.run_security_scans == true }}
run: echo "Performing static security analysis on deployment manifests..."
- name: Apply Deployment
run: |
echo "Deploying ${{ inputs.application_name }} to cluster..."
echo "Scaling deployment to ${{ inputs.replicas }} pods..."
- name: Confirm Deployment Completion
run: echo "Deployment of ${{ inputs.application_name }} completed successfully."
2. Microservice Calling Workflow
Path: .github/workflows/payment-service-deploy.yml
name: "Payment Service Pipeline (Calling Workflow)"
on:
workflow_dispatch:
push:
branches:
- main
jobs:
run-unit-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Execute Payment Unit Tests
run: echo "Executing test suite for Payment Microservice..."
build-payment-artifact:
runs-on: ubuntu-latest
needs: [run-unit-tests]
steps:
- name: Build Payment Service Artifacts
run: echo "Compiling binary and generating container image..."
deploy-payment-service:
needs: [build-payment-artifact]
uses: ./.github/workflows/deploy.yml
with:
application_name: "payment-service"
run_security_scans: true
replicas: 5
Execution Order & Dependency Flow
The needs: keyword establishes an explicit job execution chain across local and imported reusable workflows:
10. Action Inputs Overview & Advanced Considerations
The third type of input parameter supported by GitHub Actions is Action Inputs. Unlike workflow inputs or reusable workflow inputs, action inputs pass parameters to custom actions executing at the step level.
Syntax Preview (Theory)
Custom actions declare parameters inside an action.yml file:
# Inside custom action definition (action.yml)
inputs:
image_name:
description: "Name of the container image to scan"
required: true
Workflows supply these parameters within individual job steps using the with: syntax:
# Inside workflow step
- name: Run Docker Security Scan Action
uses: my-org/docker-scan-action@v1
with:
image_name: "payment-service:v1.0.1"
Note: Action inputs require a deep understanding of custom action construction (JavaScript actions, Docker container actions, or Composite actions). Custom action development is covered in subsequent chapters of this course.
11. Summary and Key Takeaways
Summary and Key Takeaways
- Dynamic CI/CD Pipelines: Inputs eliminate hardcoded parameters, allowing workflows to adapt dynamically to environments (
dev,QA,prod), operational settings, and deployment targets at runtime. - Three Input Patterns: GitHub Actions categorizes inputs into Workflow Inputs (
workflow_dispatch), Reusable Workflow Inputs (workflow_call), and Action Inputs (with:inside steps). - Multi-Channel Dispatch Triggering: Manual
workflow_dispatchpipelines can be executed via the GitHub Web UI, terminal commands using GitHub CLI (gh workflow run), or automated REST API requests. - Type Safety Over Freeform Strings: Prefer the
choicedata type with drop-down values over freeformstringfields to prevent human typographical errors during manual pipeline execution. - Logic Decoupled from Data: Inputs provide raw data values via the
${{ inputs.<name> }}expression context, while conditional expressions (if:) handle execution logic based on that data. - Enterprise Centralization: Reusable workflows (
workflow_call) mirror patterns like Jenkins Shared Libraries, enabling organizations to write core pipeline logic once and share it across dozens of microservice repositories. - Safe Registry Push Strategies: Configure environment-aware steps so transient builds (such as
dev) validate locally on the runner without pushing untested image tags to public or private image registries. - Sequential Job Control: Leverage the
needs:array syntax to enforce strict dependency sequencing (tests->build->reusable deployment workflow) across local and imported jobs.