Introduction:
Custom GitHub Actions has revolutionized the software development workflow, offering a robust and flexible platform for automating tasks. While the built-in options cover a wide range, the true magic lies in custom actions, allowing you to tailor automation to your specific needs. In this blog, we’ll delve into the three main types of custom actions and explore how they can supercharge your development process.
To learn more about GitHub Actions read our blog Unleash the Power of Automation with GitHub Actions.
Three types of Custom GitHub Actions:
- Composite Actions
- Docker Container Actions
- JavaScript Actions
1. Composite Actions:
Combine existing actions (both built-in and custom) into a single workflow, creating powerful and reusable automation.
Example:



- Create test_addition.yaml file inside the .github/workflows folder
File Name:
test_addition.yaml Code:
name: "Composite Actions"
on: workflow_dispatch
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: "checkout repository"
uses: actions/checkout@v4
- name: calling_custom_action
uses: ./test_actions
with:
Var1: 4
Var2: 2 - Create actions.yaml and addition.py file inside the test_actions folder.
File Name:
actions.yaml Code:
name: "addition"
description: "performing addition of two variables"
inputs:
Var1:
description: "Value of Var1..."
required: true
Var2:
description: "Value of Var2..."
required: true
runs:
using: composite
steps:
- name: Executing python script
id: calculator
shell: bash
env:
A: ${{ inputs.Var1 }}
B: ${{ inputs.Var2 }}
run: |
python3 ${{ github.action_path }}/addition.py - runs key is used to specify the environment in which a job or step should run.
- When runs is configured with using: composite, it means that the job or step will run a series of steps defined as a composite run steps action. Composite run steps allow you to define and reuse sets of steps across multiple workflows or jobs.
File Name:
addition.py Code:
import os
def addition(num1: int, num2: int) -> int:
return num1 + num2
def main():
num1 = int(os.getenv('A', 0))
num2 = int(os.getenv('B', 0))
add = addition(num1, num2)
print(f"addition is: {add}") 2. Docker Container Actions:
Package your action’s logic within a Docker container, leveraging pre-built environments and dependencies. This ensures consistency, isolation, and portability across different systems.
Example:



- test_addition.yaml and addition.py file will be the same in this action. Basically, in docker actions, we need to add one file which is Dockerfile to build the container and need to slightly update an actions.yaml file.
File Name:
actions.yaml Code:
name: "addition"
description: "performing addition of two variables"
inputs:
Var1:
description: "Value of Var1..."
required: true
Var2:
description: "Value of Var2..."
required: true
runs:
using: 'docker'
image: 'Dockerfile' - runs is configured with using: ‘docker’, it means that the job or step will be executed within a Docker container.
- image: ‘Dockerfile’: Specifies the Docker image to use for running the job or step. In this case, ‘Dockerfile’ is likely referring to a Dockerfile in your repository’s root directory that defines the configuration for building the Docker image. The value provided here should be the name of the Docker image or the path to a Dockerfile.
File Name:
Dockerfile Code:
FROM python:3
COPY addition.py /addition.py
RUN chmod +x addition.py
ENTRYPOINT ["python", "/addition.py"] 3. JavaScript Actions:
Write your action’s logic directly in JavaScript, offering flexibility and rapid development. Perfect for quick scripts and simple tasks.
Example:



File Name:
test_addition.yaml Code:
name: "Javascript actions"
on: workflow_dispatch
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: "checkout repository"
uses: actions/checkout@v4
- name: install deps
run: |
npm install @actions/core
- name: calling_custom_action
uses: ./test_actions
with:
Var1: 4
Var2: 2 File Name:
actions.yaml Code:
name: "addition"
description: "performing addition of two variables"
inputs:
Var1:
description: The first number to add.
Var2:
description: The second number to add.
runs:
using: 'node20'
main: 'index.js' - runs is configured with using: ‘node20’, it means that using: ‘node20’ Specifies that the job or step will run using Node.js version 20.x. GitHub Actions provides pre-configured environments for different programming languages and tools, including specific versions of Node.js. In this case, node20 likely refers to Node.js version 20.x.
- main: ‘index.js’: Specifies the entry point for the execution. In this case, ‘index.js’ is likely the main JavaScript file for your application or project. When the job or step runs, it will execute the code in index.js.
File Name:
index.js Code:
const core = require('@actions/core');
const num1 = parseInt(core.getInput('Var1'));
const num2 = parseInt(core.getInput('Var2'));
if (isNaN(num1) || isNaN(num2)) {
core.setFailed('Invalid input: Please enter valid numbers.');
return;
}
const sum = num1 + num2;
console.log(`The sum of ${num1} and ${num2} is ${sum}`); Choosing the Right Action:
- Complexity of the task: For complex tasks, Docker container actions offer more control and isolation. Simple tasks can be handled by JavaScript actions.
- Need for specific tools: If you need specific tools or frameworks, Docker container actions are the way to go.
- Ease of development: JavaScript actions are easier to develop if you’re familiar with JavaScript.
- Reusability: Composite actions are ideal for creating reusable workflows.
Conclusion:
Custom GitHub actions empower you to automate tasks, streamline your workflow, and focus on what truly matters – building great software. With the flexibility of Docker container actions, the agility of JavaScript actions, and the orchestration power of composite actions.
















