Steps
Step schema, shell commands (run), execution image (image), template references (uses/with)
A Step is the smallest unit of execution that runs sequentially within a Job. Each Step is defined using either a shell command (run) or a template reference (uses).
Below is an example of a Step execution log.
Below is an example of an error log from a failed Step.
Step Schema
| Field | Required | Type | Description |
|---|---|---|---|
name | YES (object form) | string | Step name (1-255 chars, [a-zA-Z0-9_-]) |
run | NO | string | Shell command to execute. Cannot be used together with uses |
image | NO | string | Image to run the command in |
env | NO | object | Step-level environment variables |
uses | NO | string | Template reference (\{owner\}/\{name\}@\{version\} format). Cannot be used together with run |
with | NO | object | Input parameters to pass to the template (when using uses) |
id | NO | string | Identifier for referencing Step outputs |
working-directory | NO | string | Working directory override (relative path, must not contain ..) |
timeout-minutes | NO | int | Step timeout in minutes (must be positive, only supported with run) |
Shorthand Syntax
Simple commands can be written as shorthand strings.
steps:
# Shorthand — writing just a string is treated as run
- npm install
- npm test
- npm run buildThe above is equivalent to:
steps:
- name: npm-install
run: npm install
- name: npm-test
run: npm test
- name: npm-run-build
run: npm run buildrun (Shell Command Execution)
run executes shell commands. It supports both single commands and multiline scripts.
Each Step runs in an isolated environment, so you can use any shell command available in the specified image. Tools like npm, python, go, make, curl, wget, and more can all be used as long as they are installed in the image.
The shell used is /bin/sh (POSIX sh). If you need Bash-specific syntax ([[ ]], arrays, etc.), add #!/bin/bash at the top of your script, provided Bash is installed in the image.
Single Command
steps:
- name: install
run: npm ci
image: node:18Multiline Script
Use YAML's | (literal block) to write multiline scripts.
steps:
- name: build-and-test
image: node:18
run: |
# Install dependencies
npm ci
# Run lint checks
npm run lint
# Run unit tests
npm test
# Production build
npm run buildVarious Tool Examples
You can run any command as long as it is available in the specified image.
steps:
# Go build
- name: build-go
image: golang:1.22
run: |
go mod download
go build -o app ./cmd/server
# Python tests
- name: test-python
image: python:3.12
run: |
pip install -r requirements.txt
pytest tests/ --cov=src
# API call with cURL
- name: health-check
image: alpine:3.19
run: |
apk add --no-cache curl
curl -f https://api.example.com/health
# Run a custom shell script
- name: custom-script
image: ubuntu:24.04
run: |
chmod +x ./scripts/deploy.sh
./scripts/deploy.shUsing Environment Variables
steps:
- name: deploy
image: alpine:3.19
env:
DEPLOY_ENV: production
API_URL: "https://api.example.com"
run: |
echo "Deploying to $DEPLOY_ENV"
echo "API: $API_URL"
./deploy.shimage (Execution Image)
Each Step runs independently in the specified image environment. Use image to specify the image.
steps:
# Build in a Node.js 18 image
- name: build
run: npm run build
image: node:18
# Test in a Python 3.11 image
- name: test-python
run: pytest tests/
image: python:3.11
# Official Docker image (specific registry)
- name: custom
run: ./run.sh
image: asia-northeast3-docker.pkg.dev/my-project/my-repo/my-image:latestIf image is omitted, the default image ubuntu:24.04 is used. It is recommended to explicitly specify an image that includes the tools you need.
uses (Template Reference)
uses references a predefined template to execute a Step. Use with to pass input parameters.
Format
uses: "{owner}/{name}@{version}"Example: Source Code Checkout
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
# Using an HTTPS URL, the platform-injected Job Token authenticates automatically.
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
# Checkout a specific branch (defaults to the trigger branch if omitted)
ref: mainExample: Docker Image Build and Push
steps:
- name: build-push
uses: "collabops/docker-build-push@v1"
with:
# Multiple tags (separated by newlines)
tags: |
my-registry/my-app:latest
my-registry/my-app:${{ collabops.sha }}
# Build arguments
build-args: |
NODE_ENV=production
API_URL=https://api.example.comExample: Slack Notification
steps:
- name: notify
uses: "collabops/slack-notify@v1"
with:
# Webhook URL (registered in secrets)
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
# Notification message
message: "Deployment complete: ${{ collabops.ref_name }} (${{ collabops.sha }})"
title: "Deploy Success"
color: goodrun and uses Are Mutually Exclusive
run and uses cannot be used together in a single Step.
run and uses cannot be used at the same time. Each Step must specify exactly one of them.
# Correct usage
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: build
run: npm run build
image: node:18
# Incorrect usage — run and uses cannot be used together
- name: invalid
uses: "collabops/checkout@v2"
run: npm run buildid (Step Output Reference)
By specifying an id, you can reference that Step's output values from other Steps.
steps:
# 1. Save version information to output
- name: prepare-version
id: version
image: node:18
run: |
# Extract version from package.json
VERSION=$(node -p "require('./package.json').version")
# Save as key=value pairs to $COLLABOPS_OUTPUT
echo "app_version=${VERSION}" >> $COLLABOPS_OUTPUT
echo "build_date=$(date -u +%Y%m%d)" >> $COLLABOPS_OUTPUT
# 2. Use the saved output values in another Step
- name: build-image
run: |
echo "Building version: ${{ steps.version.outputs.app_version }}"
echo "Build date: ${{ steps.version.outputs.build_date }}"
docker build \
--build-arg VERSION=${{ steps.version.outputs.app_version }} \
-t my-app:${{ steps.version.outputs.app_version }} .Step Name Rules
Allowed characters: [a-zA-Z0-9_-]
Length: 1-255 characters
Must be unique within the same Job
working-directory
Overrides the working directory for a Step. Only relative paths are allowed.
steps:
- name: test-frontend
run: npm test
image: node:18
working-directory: frontend
- name: test-backend
run: npm test
image: node:18
working-directory: backendworking-directory must be a relative path and cannot contain ...
timeout-minutes
Sets a timeout for a Step or Job. If execution exceeds the specified time, it is automatically terminated.
steps:
- name: long-test
run: npm run test:e2e
image: node:18
timeout-minutes: 30timeout-minutes is only supported with run. It cannot be used with uses.
Unsupported Features
| Feature | Alternative |
|---|---|
Step-level if | Use Job-level if or shell conditionals inside run |
Step-level Condition Alternative
Since Step-level if is not supported, you can achieve the same effect using shell conditionals inside run.
steps:
- name: conditional-deploy
run: |
# Implement Step-level condition using shell conditional
if [ "$DEPLOY_ENV" = "production" ]; then
echo "Deploying to production..."
./deploy-prod.sh
else
echo "Skipping production deploy"
fi
env:
DEPLOY_ENV: ${{ vars.DEPLOY_ENV }}