How to standardize and supercharge your CI/CD pipelines across projects
When your teams manage multiple projects with similar deployment patterns, repeating the same GitHub Actions steps over and over can become tedious, error-prone, and hard to maintain
Thankfully, GitHub Actions offers two powerful solutions to help standardize, reuse, and scale your CI/CD pipelines: Composite Actions and Reusable Workflows. When used together, they form a clean, modular, and DRY (don’t repeat yourself) CI/CD strategy
🔄 Composite Actions vs Reusable Workflows
🧱 Composite Actions
Composite Actions allow you to group steps (like docker build
, terraform plan
, or trivy scan
) into a reusable component. Think of it like a function.
Best for:
- Reusing logic (e.g., build and push images)
- Hiding complex logic from the main workflow
- Keeping workflows minimal and maintainable
Use it with:
uses: ./.github/actions/your-action
🔁 Reusable Workflows
Reusable Workflows are full workflows that can be invoked with inputs and secrets.
Best for:
- High-level CI/CD orchestration (build, test, scan, deploy)
- Enforcing common practices across repositories
- Abstracting full pipelines
Use it with:
uses: org/repo/.github/workflows/your-workflow.yml@ref
🐳 Example: Docker Build and Scan with Trivy
Here is an example of a composite action to build and push a Docker image to Azure Container Registry (ACR) and scan it using Trivy.
.github/actions/build-and-scan/action.yml
name: Docker Build and Push
inputs:
dockerfile:
default: Dockerfile
context:
default: .
image_name:
required: true
tag:
required: true
build_args:
default: ""
report_name:
default: trivy-report
runs:
using: "composite"
steps:
- uses: azure/login@v2
with:
creds: ${{ env.AZURE_CREDENTIALS }}
- uses: azure/docker-login@v2
with:
login-server: ${{ env.CONTAINER_REGISTRY }}
username: ${{ env.ACR_USERNAME }}
password: ${{ env.ACR_PASSWORD }}
- name: Build and Push Image
shell: bash
run: |
docker build ${{ inputs.build_args }}
-t ${{ env.CONTAINER_REGISTRY }}/${{ inputs.image_name }}:${{ inputs.tag }}
-f "${{ inputs.dockerfile }}" "${{ inputs.context }}"
docker push ${{ env.CONTAINER_REGISTRY }}/${{ inputs.image_name }}:${{ inputs.tag }}
- name: Scan with Trivy
uses: aquasecurity/trivy-action@0.32.0
with:
image-ref: '${{ env.CONTAINER_REGISTRY }}/${{ inputs.image_name }}:${{ inputs.tag }}'
format: 'sarif'
output: 'trivy-results.sarif'
exit-code: 0
- name: Upload SARIF to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
category: trivy
Usage in Workflow
- name: Build and Scan
uses: ./.github/actions/build-and-scan
with:
image_name: my-app
tag: ${{ github.sha }}
🌍 Example: Terraform/Terragrunt Validation with Checkov
Now let’s see a reusable workflow to validate Terraform code and scan for misconfigurations using Checkov.
.github/workflows/infra-check.yml
name: Infra Validation Workflow
on:
workflow_call:
inputs:
working_dir:
required: true
type: string
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Terragrunt and OpenTofu
run: |
curl -s https://raw.githubusercontent.com/opentofu/opentofu/main/scripts/install.sh | bash
curl -L https://github.com/gruntwork-io/terragrunt/releases/latest/download/terragrunt_linux_amd64 -o terragrunt
chmod +x terragrunt
sudo mv terragrunt /usr/local/bin/
- name: Validate HCL Syntax
run: |
terragrunt hclfmt --terragrunt-check --terragrunt-diff --recursive
working-directory: ${{ inputs.working_dir }}
- name: Check Misconfigurations with Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: ${{ inputs.working_dir }}
quiet: true
Usage in Project Workflow
jobs:
call-validation:
uses: your-org/your-repo/.github/workflows/infra-check.yml@main
with:
working_dir: infrastructure/staging/eu-west-1
⚙️ Best Practices
✅ Keep composite actions in .github/actions
✅ Keep reusable workflows in .github/workflows
✅ Abstract frequently repeated patterns
✅ Use inputs, outputs, and env vars to increase flexibility
✅ Use workflow_call
and workflow_dispatch
to structure triggers
✅ Defer secrets to the calling workflow
💡 Conclusion
Using composite actions and reusable workflows together can transform your CI/CD processes into clean, repeatable, and secure pipelines. Whether you’re building containers, provisioning infrastructure, or scanning for vulnerabilities, this modular approach will scale with your teams and your systems.
Enjoy building better pipelines !