Reusable GitHub Custom Actions
Transforming repetitive CI/CD tasks into shareable, maintainable automation components.
Every development team faces the same frustrating reality: copying and pasting the same workflow configurations across dozens of repositories, watching minor updates cascade into hours of tedious maintenance work across every project. GitHub Custom Actions solve this problem by transforming your repetitive automation tasks into reusable, versionable components that can be shared across your entire organization. Instead of managing hundreds of nearly-identical workflow files, you can build sophisticated automation libraries that enforce standards, reduce duplication, and scale effortlessly as your codebase grows.
At this article, I will walk you through the Custom Action creation process and how to use them in our workflows.
What is a GitHub Custom Action?
A GitHub Custom Action is a reusable unit of code that encapsulates specific functionality within GitHub Actions workflows. Unlike standard workflow files that live within individual repositories, custom actions can be packaged, versioned, and shared across multiple projects and organisations. They serve as building blocks that abstract complex operations into simple, parameterised interfaces.
Custom actions come in three primary types:
Docker container actions - Run in isolated containers with full control over the environment
JavaScript actions - Execute directly on runners with fast startup times
Composite actions - Combine multiple workflow steps into a single reusable action
Why Use Custom Actions?
Custom actions address several critical pain points in modern DevOps workflows by providing code reusability that eliminates the need to copy and paste similar configurations across repositories. They ensure consistency by allowing teams to enforce standardised processes organisation-wide, while abstracting complex multi-step operations into clean, readable interfaces.
The versioning capabilities enable teams to pin to stable releases while testing newer versions, and the thriving GitHub Marketplace ecosystem provides access to thousands of community-built solutions for common automation tasks.
When to Use Custom Actions
Consider creating custom actions when you encounter repeated workflow patterns across multiple repositories, or when dealing with complex multi-step operations that require intricate setup and coordination or an action that doesn’t exist in the marketplace specific to your tasks and organisation. They become essential for enforcing organisation standards, integrating with proprietary tools that lack existing marketplace actions, and managing cross-repository dependencies.
Common scenarios include code quality enforcement through linting and formatting, security vulnerability scanning, deployment to specific platforms, database operations, documentation generation, and integration with internal APIs and notification systems.
How to Store the Custom Actions
The action.yml
file must be placed in the root directory of the repository that contains the custom action. This is completely separate from workflows. Custom actions are not stored in the same location as workflows. We can store actions in three different alternative scenarios:
Dedicated Action Repository
We can have a dedicated repository for the custom action.
my-custom-action/
├── action.yml # Action definition at root
├── README.md
└── src/ # Any supporting files
Mixed Repository
We can combine the action and workflow files in the same repository within different folders.
my-project/
├── action.yml # Custom action at root
├── .github/
│ └── workflows/
│ └── ci.yml # Workflows in standard location
├── src/ # Application code
└── README.md
Multiple Actions in One Repository
We can have multiple composite actions in a single repository by placing them in separate directories, each with its own action.yml
file.
my-actions-collection/
├── python-linting/
│ └── action.yml
├── docker-build/
│ └── action.yml
└── README.md
When referencing our custom action from a workflow, we use the repository path.
Demo: Python Linting Custom Action
Let's transform the original reusable workflow into a proper custom action. Create an action.yml
file that defines the action metadata and behaviour.
The key element here is using: 'composite'
, which tells GitHub Actions this is a composite action that bundles multiple workflow steps into a single reusable component. Unlike JavaScript actions that run in Node.js environments or Docker actions that require containers, composite actions execute directly on the same runner as your main workflow, making them fast and lightweight. They act like mini-workflows that can combine shell commands, marketplace actions, and environment manipulations, though they cannot call other custom actions you've created. Each step must explicitly declare its shell type, and the composite action essentially extends your existing workflow by packaging common step sequences into shareable components:
name: 'Python Code Quality Check'
description: 'Run Python linting with Black formatter'
inputs:
python-version:
description: 'Python version to use'
required: false
default: '3.9'
source-path:
description: 'Path to Python source code'
required: false
default: '.'
runs:
using: 'composite' # Composite Action
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ inputs.python-version }}
- name: Install Black
shell: bash
run: pip install black
- name: Run Black formatting check
shell: bash
run: black --check --diff ${{ inputs.source-path }}
Teams can now use this action across repositories with clean, simple syntax:
name: Python Code Quality
on: [push, pull_request]
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: your-org/python-linting-action@v1
with:
python-version: '3.11'
source-path: 'src/'
This custom action provides better parameterisation and encapsulation compared to the original reusable workflow, making it easier to maintain and share across projects while keeping the interface simple and focused.
Conclusion
Custom GitHub Actions represent a fundamental shift from ad-hoc workflow scripts to engineered, reusable automation components that scale across organisations. By encapsulating complex operations behind clean interfaces, they reduce maintenance overhead, ensure consistency, and enable teams to build robust CI/CD ecosystems.
The investment in well-designed custom actions pays dividends through reduced duplication, improved reliability, and faster development cycles, making them indispensable tools in any serious development workflow arsenal.