All skills
Skillintermediate
Custom GitHub Actions Guide
**Last Updated:** December 2025
Claude Code Knowledge Pack7/10/2026
Overview
Custom GitHub Actions Guide
Last Updated: December 2025
This guide covers creating custom GitHub Actions: composite, Docker, and JavaScript actions with proper metadata, directory structure, and versioning.
Table of Contents
Action Types
| Type | Runtime | Use Case | Performance |
|---|---|---|---|
| Composite | Shell/Actions | Combine multiple steps | Fast startup |
| Docker | Container | Custom environment/tools | Slower startup |
| JavaScript | Node.js | API interactions, complex logic | Fastest |
Action Metadata
Branding
Add branding to make your action visually distinctive in GitHub Marketplace:
name: 'Setup Node.js with Cache'
description: 'Setup Node.js with automatic dependency caching'
author: 'Your Name or Organization'
branding:
icon: 'package' # Feather icon name
color: 'blue' # Available: white, yellow, blue, green, orange, red, purple, gray-dark
inputs:
node-version:
description: 'Node.js version to use'
required: true
Available Icons: See Feather Icons - e.g., package, box, server, code, git-branch, shield, check-circle
Best Practices:
- Choose icons that represent the action's purpose
- Use consistent branding across related actions
- Branding is required for GitHub Marketplace publishing
Directory Structure
Local Repository Actions
Use .github/actions/ for actions within the same repository:
repository-root/
├── .github/
│ ├── actions/ # Local custom actions
│ │ ├── setup-node-cached/ # Composite action
│ │ │ ├── action.yml
│ │ │ └── README.md
│ │ ├── terraform-validator/ # Docker action
│ │ │ ├── action.yml
│ │ │ ├── Dockerfile
│ │ │ ├── entrypoint.sh
│ │ │ └── README.md
│ │ └── label-pr/ # JavaScript action
│ │ ├── action.yml
│ │ ├── dist/
│ │ │ └── index.js # Compiled/bundled JS
│ │ ├── src/
│ │ │ └── index.ts # Source TypeScript
│ │ ├── package.json
│ │ └── README.md
│ └── workflows/
│ └── ci.yml
Usage in Workflows:
steps:
# Local action (same repository)
- uses: ./.github/actions/setup-node-cached
with:
node-version: '20'
# Action from another repository
- uses: owner/repo/.github/actions/action-name@v1
Standalone Action Repositories
For actions intended for GitHub Marketplace or cross-repo reuse:
action-repository-root/
├── action.yml # Action definition (MUST be in root)
├── README.md # Usage documentation
├── LICENSE # License file
├── CHANGELOG.md # Version history
├── dist/ # Compiled code (JS actions)
│ └── index.js
├── src/ # Source code (JS actions)
│ └── index.ts
└── Dockerfile # For Docker actions
Best Practices:
- Use
.github/actions/for repository-local actions - Create separate repos for reusable/Marketplace actions
- Always include README.md with usage examples
- For JS actions, commit compiled
dist/(don't gitignore)
Versioning
Semantic Versioning
Use MAJOR.MINOR.PATCH format:
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes
Git Tags
# Create version tag
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
# Update major version tag (v1 → latest v1.x.x)
git tag -fa v1 -m "Update v1 to v1.0.0"
git push origin v1 --force
Tag Strategy
Maintain multiple tag levels:
- Specific:
v1.0.0,v1.0.1,v1.1.0 - Major:
v1,v2(points to latest minor/patch)
User options:
- uses: owner/action@v1.0.0 # Pinned to exact version
- uses: owner/action@v1 # Latest v1.x.x
- uses: owner/action@abc123 # Pinned to SHA (most secure)
Release Workflow
# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Create GitHub Release
run: gh release create ${{ github.ref_name }} --generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update major version tag
run: |
MAJOR=$(echo ${{ github.ref_name }} | cut -d. -f1)
git tag -fa $MAJOR -m "Update $MAJOR tag"
git push origin $MAJOR --force
Breaking Changes
When introducing breaking changes:
- Document in CHANGELOG.md and release notes
- Increment MAJOR version
- Provide migration guide
- Consider maintaining previous major version branch
Publishing to Marketplace
Requirements
- Repository must be public
- action.yml in repository root
- Branding metadata (icon and color)
- README.md with usage examples
- Semantic version tags
Marketplace Listing
- Go to repository Settings → Actions → "Create Action"
- Or visit:
https://github.com/marketplace/actions/your-action - Fill in marketplace details
- Submit for review
Pre-release Testing
Use pre-release versions for testing:
git tag -a v1.0.0-beta.1 -m "Beta release"
git push origin v1.0.0-beta.1
Action Templates
Composite Action Template
name: '[Action Name]'
description: '[Brief description]'
author: '[Author]'
branding:
icon: 'check-circle'
color: 'green'
inputs:
input-name:
description: '[Description]'
required: true
default: '[default value]'
outputs:
output-name:
description: '[Description]'
value: ${{ steps.step-id.outputs.value }}
runs:
using: 'composite'
steps:
- name: Step name
id: step-id
shell: bash
run: echo "value=result" >> $GITHUB_OUTPUT
Docker Action Template
name: '[Action Name]'
description: '[Brief description]'
author: '[Author]'
branding:
icon: 'box'
color: 'blue'
inputs:
input-name:
description: '[Description]'
required: true
outputs:
output-name:
description: '[Description]'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.input-name }}
JavaScript Action Template
name: '[Action Name]'
description: '[Brief description]'
author: '[Author]'
branding:
icon: 'code'
color: 'purple'
inputs:
github-token:
description: 'GitHub token for API access'
required: true
outputs:
result:
description: 'Action result'
runs:
using: 'node20'
main: 'dist/index.js'
Summary
| Aspect | Recommendation |
|---|---|
| Location | .github/actions/ for local, separate repo for shared |
| Branding | Required for Marketplace, recommended for all |
| Versioning | Semantic versions with major tag updates |
| Documentation | README.md with examples, CHANGELOG.md |
| Security | Pin to SHA, minimal permissions |