GitHub Actions Tutorial — Action Metadata
Action Metadata
Every custom action requires an action.yml (or action.yaml) file in its root directory. This file defines the action’s interface — its name, inputs, outputs, runtime, and branding.
Complete action.yml Reference
name: 'Deploy to S3'
description: 'Upload files to an AWS S3 bucket'
author: 'my-org'
branding:
icon: 'upload-cloud'
color: 'orange'
inputs:
bucket:
description: 'S3 bucket name'
required: true
path:
description: 'Local path to upload'
required: false
default: './dist'
aws-region:
description: 'AWS region'
required: false
default: 'us-east-1'
outputs:
url:
description: 'Uploaded file URL'
value: ${{ steps.upload.outputs.url }}
runs:
using: 'composite'
steps:
- name: Upload to S3
id: upload
run: |
aws s3 sync ${{ inputs.path }} s3://${{ inputs.bucket }}/ --region ${{ inputs.aws-region }}
echo "url=https://${{ inputs.bucket }}.s3.amazonaws.com/index.html" >> "$GITHUB_OUTPUT"
shell: bash
Top-Level Fields
| Field | Required | Description |
|---|---|---|
name |
✅ | Action name (shown in the Marketplace) |
description |
✅ | Short description |
author |
❌ | Author name or organization |
branding |
❌ | Icon and color for Marketplace listing |
Inputs
inputs:
<input-id>:
description: 'What this input does'
required: true # or false
default: 'default-value' # optional
deprecationMessage: 'Use new-input instead' # optional
- All inputs are passed as strings
required: truedoesn’t prevent the workflow from running — it’s informational in composite actions- Access in steps:
${{ inputs.input-id }}
Outputs
outputs:
<output-id>:
description: 'What this output contains'
value: ${{ steps.<step-id>.outputs.<key> }}
For JavaScript actions, outputs are set via core.setOutput(). For composite actions, use $GITHUB_OUTPUT in a step and reference it in the output value.
Runs Configuration
Composite
runs:
using: 'composite'
steps:
- run: echo "hello"
shell: bash
JavaScript
runs:
using: 'node20'
main: 'dist/index.js'
pre: 'setup.js' # optional — runs before main
post: 'cleanup.js' # optional — runs after main
Docker
runs:
using: 'docker'
image: 'Dockerfile' # or 'docker://image:tag'
args:
- ${{ inputs.path }}
env:
MY_VAR: 'value'
Branding
For Marketplace listing, choose an icon and color:
branding:
icon: 'upload-cloud' # Feather icon name
color: 'blue' # white, yellow, blue, green, orange, red, purple, gray-dark
Feather Icons — use the icon name from the site.
Pre and Post Scripts (JavaScript Only)
runs:
using: 'node20'
pre: 'src/setup.js' # runs before the main entry point
main: 'src/index.js' # main entry point
post: 'src/cleanup.js' # runs after all steps (even on failure)
post-if: 'always()' # condition for post script
Use cases:
pre:— set up authentication, start servicespost:— cleanup resources, revoke tokens
Common Mistakes
| Mistake | Fix |
|---|---|
Missing action.yml |
Must be in the action’s root directory |
required: true not enforced |
It’s informational — add validation in your action code |
| Output value empty | Ensure the step ID matches and output is set correctly |
| Branding icon not found | Use exact Feather icon names |
Quick Reference
| Section | Key Fields |
|---|---|
| Identity | name, description, author |
| Inputs | description, required, default |
| Outputs | description, value |
| Runs (composite) | using: 'composite', steps: |
| Runs (JS) | using: 'node20', main:, pre:, post: |
| Runs (Docker) | using: 'docker', image:, args: |
| Branding | icon:, color: |
← Previous: Docker Actions
Next: Publishing to Marketplace →