GitHub Actions Cheatsheet
Deployment
Use this GitHub Actions reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Deployment Environments
Environments add protection rules, required reviewers, and scoped secrets to deployment jobs.
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com # shown in the Actions UI and PR deployments
steps:
- run: ./deploy.sh
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} # from 'production' environmentConfigure environments at: Repo → Settings → Environments.
Environment Protection Rules
| Rule | What it does |
|---|---|
| Required reviewers | Job pauses and notifies reviewers; must be approved to proceed |
| Wait timer | Delays job start by N minutes (1–43,200) |
| Deployment branches | Restrict which branches/tags can deploy |
| Deployment policies | Custom rules (Enterprise) |
Branch Protection via Environments
# Only allow main and release/* to deploy to production
# Set in: Settings → Environments → production → Deployment branches
# Pattern: main, release/**In the workflow, this blocks the job from running on other branches — no code change needed.
Concurrency — Prevent Duplicate Deployments
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false # queue, don't cancel (safe for deploys)Or cancel for preview/staging:
concurrency:
group: deploy-preview-${{ github.event.pull_request.number }}
cancel-in-progress: trueDeploy on Push to Main
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- run: ./scripts/deploy.sh
env:
API_KEY: ${{ secrets.API_KEY }}Deploy on Release Publish
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}
- run: echo "Deploying ${{ github.event.release.tag_name }}"
- run: ./deploy.shDeploy to AWS (OIDC — no static keys)
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActions
aws-region: us-east-1
- uses: aws-actions/amazon-ecr-login@v2
- run: |
docker build -t $ECR_URI:${{ github.sha }} .
docker push $ECR_URI:${{ github.sha }}
env:
ECR_URI: 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp
- run: |
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--force-new-deploymentDeploy to Google Cloud (OIDC)
permissions:
id-token: write
contents: read
steps:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/123/locations/global/workloadIdentityPools/github/providers/github
service_account: deployer@my-project.iam.gserviceaccount.com
- uses: google-github-actions/deploy-cloudrun@v2
with:
service: my-service
image: gcr.io/my-project/app:${{ github.sha }}
region: us-central1Deploy to Azure (OIDC)
permissions:
id-token: write
contents: read
steps:
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: azure/webapps-deploy@v3
with:
app-name: my-app
package: dist/GitHub Pages Deployment
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-pages-artifact@v3
with:
path: out/
- id: deploy
uses: actions/deploy-pages@v4Preview / PR Environments
on:
pull_request:
types: [opened, synchronize, reopened, closed]
jobs:
deploy-preview:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
environment:
name: pr-${{ github.event.number }}
url: https://pr-${{ github.event.number }}.preview.example.com
steps:
- run: ./deploy-preview.sh ${{ github.event.number }}
teardown:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- run: ./teardown-preview.sh ${{ github.event.number }}Post Deployment Status to PR
- uses: actions/github-script@v7
with:
script: |
github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: '${{ steps.deploy.outputs.deployment-id }}',
state: 'success',
environment_url: 'https://example.com',
description: 'Deploy complete',
});Or use the simpler PR comment approach:
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '**Deployed to production:** https://example.com',
});Rollback Pattern
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
previous-sha: ${{ steps.get-prev.outputs.sha }}
steps:
- id: get-prev
run: echo "sha=$(git rev-parse HEAD~1)" >> $GITHUB_OUTPUT
- run: ./deploy.sh ${{ github.sha }}
rollback:
needs: deploy
if: failure()
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh ${{ needs.deploy.outputs.previous-sha }}
env:
ROLLBACK: 'true'Deploy Workflow Checklist
- Use environment protection rules for production (required reviewers + branch restriction).
- Use OIDC over static credentials whenever the cloud provider supports it.
- Set
concurrency.cancel-in-progress: falseto queue, not clobber, concurrent deploys. - Upload build artifacts before deploy; download in deploy job — don't rebuild.
- Always record the deployed SHA/version in a step output or annotation.
- Post deployment URLs to the PR for preview environments.
- Implement a rollback job triggered on
failure().