Working with Deployment Workflows
1. Defining Deployment Jobs
| Property | Description | Values |
|---|---|---|
| jobs.<job_id>.name | Human-readable name for the job | string |
| jobs.<job_id>.runs-on | Runner environment to execute the job on | ubuntu-latest, macOS-latest, windows-latest, or custom runner labels |
| jobs.<job_id>.environment | Environment to deploy to (optional) | string or object |
| jobs.<job_id>.steps | Sequence of actions to run in the job | array of step objects |
| jobs.<job_id>.needs | Job dependencies (optional) | array of job IDs |
| jobs.<job_id>.if | Conditional expression to run the job (optional) | string |
Example: Basic Deployment Job
jobs:
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Deploy to Server
run: |
echo "Deploying application..."
environment property links to a defined environment in your repository settings, which can include protection rules and review approval requirements.
2. Using Deployment Environment
| Property | Description | Values |
|---|---|---|
| environment.name | Name of the deployment environment | production, staging |
| environment.url | URL where the deployment is accessible | https://app.example.com |
| environment.protection_rules | Protection rules to apply to the environment | wait_timer, required_approvals |
Example: Environment Configuration
name: Deploy to Production
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://app.example.com
3. Requiring Manual Approval
Manual approval is a critical security and governance feature in GitHub Actions that allows workflows to pause and await human confirmation before proceeding to the next step. This is particularly useful for deployment workflows where you want to ensure that a human reviews and approves the deployment before it happens.
| Setting | Description | Value |
|---|---|---|
| workflow_dispatch | Triggers the workflow manually from the GitHub UI or API. | true |
| on.workflow_dispatch | Enables manual triggering of the workflow. | {} |
| needs | Specifies that a job depends on another job or jobs. | approval |
Example: Manual Approval Workflow
name: Manual Approval Workflow
on:
workflow_dispatch: {}
jobs:
approval:
runs-on: ubuntu-latest
steps:
- name: Wait for manual approval
run: echo "Waiting for manual approval..."
deploy:
needs: approval
runs-on: ubuntu-latest
steps:
- name: Deploy to production
run: echo "Deploying to production..."
workflow_dispatch trigger allows the workflow to be manually triggered from the GitHub UI or API, which is useful for workflows that require human intervention.
4. Setting Deployment URL
| Property | Description | Example |
|---|---|---|
| github.event.deployment.url | URL of the deployment, set by GitHub | https://example.com/deployment/12345 |
| env.DEPLOYMENT_URL | Environment variable to store deployment URL | https://myapp.vercel.app |
Example: Set Deployment URL in Environment
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to Vercel
run: |
DEPLOYMENT_URL=$(vercel --prod)
echo "DEPLOYMENT_URL=$DEPLOYMENT_URL" >> $GITHUB_ENV
5. Tracking Deployment Status
Example: Using GitHub API to Check Deployment Status
const { Octokit } = require("@octokit/rest");
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
async function checkDeploymentStatus(owner, repo, deploymentId) {
try {
const response = await octokit.request("GET /repos/{owner}/{repo}/deployments/{deployment_id}", {
owner,
repo,
deployment_id: deploymentId
});
console.log("Deployment Status:", response.data.status);
return response.data;
} catch (error) {
console.error("Error fetching deployment status:", error);
}
}
checkDeploymentStatus("octocat", "Hello-World", 123456);
| Field | Description | Values |
|---|---|---|
| status | Current status of the deployment | success, failure, pending, error |
| environment | Name of the environment the deployment targets | production, staging, development |
| created_at | Timestamp when the deployment was created | 2023-04-15T10:00:00Z |
| updated_at | Timestamp when the deployment was last updated | 2023-04-15T11:00:00Z |
github.rest.repos.createDeploymentStatus endpoint.
Example: Updating Deployment Status in GitHub Actions
name: Update Deployment Status
on:
workflow_run:
workflows: ["Deploy"]
jobs:
update-status:
runs-on: ubuntu-latest
steps:
- name: Update deployment status to success
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const deploymentId = 123456;
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deploymentId,
state: "success",
description: "Deployment completed successfully"
});
6. Using Blue-Green Deployments
Blue-green deployment is a deployment strategy that reduces downtime and risk by running two identical production environments — one "blue" and one "green".
| Environment | Status | Description |
|---|---|---|
| Blue | ACTIVE | Current production environment |
| Green | INACTIVE | Staging environment with new version |
Example: GitHub Actions Workflow for Blue-Green Deployment
name: Blue-Green Deployment
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to Green
run: |
echo "Deploying new version to Green environment"
# Deployment logic here
- name: Validate Green
run: |
echo "Validating Green environment"
# Validation logic here
- name: Switch traffic to Green
run: |
echo "Switching traffic from Blue to Green"
# Traffic switch logic here
Blue-Green Deployment Benefits
- Zero Downtime: Traffic is switched atomically.
- Rollback Capability: Easily switch back to the blue environment if issues arise.
- Testing: New version can be tested in a production-like environment.
7. Implementing Canary Deployments
Canary deployments gradually roll out changes to a subset of users or servers before full deployment. This approach helps reduce risk and allows for quick rollback if issues arise.
| Aspect | Description | Implementation |
|---|---|---|
| Deployment Strategy | Gradually increase traffic to new version | Use weighted routing or percentage-based distribution |
| Traffic Splitting | Control how much traffic goes to new version | Configure with service mesh or load balancer |
| Monitoring | Track performance and errors during rollout | Use metrics like latency, error rate, and user feedback |
Example: Using GitHub Actions for Canary Deployment
name: Canary Deployment
on:
push:
branches:
- main
jobs:
deploy-canary:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to canary environment
run: |
echo "Deploying to canary..."
# Deploy logic here
- name: Validate deployment
run: |
echo "Validating canary deployment..."
# Validation logic here
- name: Gradually increase traffic
run: |
echo "Increasing traffic to canary..."
# Traffic shifting logic here
Key Benefits of Canary Deployments
- Reduced risk of full system failure
- Early detection of issues in production
- Gradual user adoption of new features
- Ability to quickly rollback if problems occur
8. Rolling Back Deployments
| Option | Values | Notes |
|---|---|---|
| github.event.inputs.rollback_to | sha or tag |
Commit SHA or tag to rollback to |
| github.event.inputs.environment | production or staging |
Environment to rollback deployment in |
Example: Rolling Back to Previous Commit
name: Rollback Deployment
on:
workflow_dispatch:
inputs:
rollback_to:
description: 'Commit SHA to rollback to'
required: true
type: string
environment:
description: 'Environment to rollback in'
required: true
type: choice
options:
- production
- staging
jobs:
rollback:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.rollback_to }}
- name: Deploy rollback
run: |
echo "Deploying to ${{ github.event.inputs.environment }} from commit ${{ github.event.inputs.rollback_to }}"
9. Using Deployment Gates
Deployment gates are conditions that must be met before a workflow can proceed to deployment. They help ensure that deployments only happen when certain criteria are satisfied.
| Gate Type | Description | Configuration | Notes |
|---|---|---|---|
| Manual Approval | Requires manual approval before deployment | needs: [approval] |
Use github.event.inputs.approval to check approval status |
| Environment Protection Rules | Enforce rules on environments (e.g., required reviewers, branches) | Defined in environment settings | Can include conditions like branch name, deployment status |
| Wait for Status Checks | Waits for specific checks to pass before proceeding | status-checks: [check-name] |
Can be used to wait for CI checks or external validation |
Example: Manual Approval Gate
jobs:
deploy:
needs: [approval]
steps:
- name: Deploy to production
run: echo "Deploying..."
Example: Environment Protection Rule
jobs:
deploy:
environment:
name: production
url: https://myapp.com
steps:
- name: Deploy to production
run: echo "Deploying..."
10. Configuring Auto-Deployments
| Option | Values | Notes |
|---|---|---|
| on | push |
Triggers workflow on push to branch |
| on | pull_request |
Triggers workflow on pull request |
| on | workflow_dispatch |
Allows manual triggering of workflow |
| env | DEPLOY_ENV |
Environment variable for deployment target |
| env | DEPLOY_TOKEN |
Token for deployment authentication |
Example: Basic Auto-Deployment Workflow
name: Deploy to Production
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Server
run: |
echo "Deploying to production server..."
Example: Conditional Deployment Based on Branch
name: Conditional Deployment
on:
push:
branches:
- main
- staging
jobs:
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to Production
run: |
echo "Deploying to production..."
11. Using Deployment Notifications
| Notification Type | Trigger | Configuration | Notes |
|---|---|---|---|
| GitHub Status Checks | Workflow completion | status: success|failure |
Shows up in PRs and commits |
| Slack Notifications | Workflow completion | slack webhook url |
Requires Slack app setup |
| Email Notifications | Workflow completion | email address |
Only for GitHub Enterprise |
| Webhook Notifications | Workflow completion | webhook url |
Custom payload support |
Example: Slack Notification
name: Slack Notification
on:
workflow_run:
workflows: ["Deploy"]
types: [completed]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send to Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
12. Monitoring Deployment History
| Field | Description | Values |
|---|---|---|
| deployment.id | Unique identifier for the deployment | 12345 |
| deployment.name | Name of the deployment | Production Deploy |
| deployment.status | Current status of the deployment | success, failure, pending |
| deployment.environment | Environment where the deployment occurred | production, staging |
| deployment.created_at | Timestamp when the deployment was created | 2025-04-01T12:00:00Z |
| deployment.updated_at | Timestamp when the deployment was last updated | 2025-04-01T12:05:00Z |
Example: Retrieve Deployment History
const { GitHub } = require("@actions/github");
async function getDeploymentHistory() {
const github = new GitHub(process.env.GITHUB_TOKEN);
const { data: deployments } = await github.rest.repos.listDeployments({
owner: "owner",
repo: "repo-name",
environment: "production"
});
console.log(deployments);
}
getDeploymentHistory();
GITHUB_TOKEN has appropriate permissions to read deployment data.