Copyright (c) 2026 MindMesh Academy. All rights reserved. This content is proprietary and may not be reproduced or distributed without permission.

5.2.1. action.yml and Required Files

💡 First Principle: GitHub locates an action by finding action.yml (or action.yaml) at the referenced path — repository root for owner/repo@ref, or a subdirectory for owner/repo/path@ref — and everything else in the repository is just code that file references.

The full contract:

name: 'Deploy to Widget Cloud'          # required — shown in logs and Marketplace
description: 'Deploys a build artifact' # required
author: 'my-org'
branding:                               # Marketplace listing only
  icon: 'upload-cloud'
  color: 'blue'
inputs:
  environment:
    description: 'Target environment'
    required: true
  timeout:
    description: 'Seconds to wait'
    required: false
    default: '300'
    deprecationMessage: 'Use wait-seconds instead'
outputs:
  url:
    description: 'Deployed URL'
    # Docker/JS: value comes from the code writing $GITHUB_OUTPUT
    # Composite: must map explicitly →
    # value: ${{ steps.deploy.outputs.url }}
runs:
  using: 'node20'
  main: 'dist/index.js'
  pre: 'dist/setup.js'
  post: 'dist/cleanup.js'
  post-if: 'success()'

Details that carry exam weight: name and description are required; input default values are strings; deprecationMessage warns consumers without breaking them; and composite actions must map each output to a step output with value:, unlike JavaScript and Docker actions where the code writes $GITHUB_OUTPUT directly. Repository layout conventionally includes a README.md (which becomes the Marketplace documentation), a LICENSE, the dist/ bundle for JavaScript actions, and — for Docker — the Dockerfile. One repository may hold multiple actions in subdirectories, but Marketplace publishing requires a single action with action.yml at the repository root (5.3.1).

The pre/post entry points deserve emphasis because only JavaScript actions have them: post runs even if the job failed (subject to post-if), making it the correct mechanism for cleanup that must always happen — revoking a temporary credential, stopping a tunnel, saving a cache.

⚠️ Exam Trap: A composite action's outputs need an explicit value: mapping in action.yml — writing to $GITHUB_OUTPUT inside a composite step is not enough to expose it to the caller. This asymmetry between composite and JS/Docker actions is a favorite distractor.

Reflection Question: Your action provisions a temporary cloud credential at the start of a job. Which runs: key guarantees revocation even when the job's later steps fail, and which action type is the only one offering it?

See how it connects
Alvin Varughese
Written byAlvin Varughese
Founder18 professional certifications