Job-level conditions
Only want to deploy when code hits the main branch? Use GitHub’s ref context:
jobs: deploy: if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - run: echo "Deploying to production"
Smart job dependencies
Sometimes you want jobs to run even when their dependencies are skipped. Here’s how to handle a deployment that should run when tests are skipped (but not when they fail):
jobs: test: if: github.event_name != 'workflow_dispatch' # Skip tests on manual trigger runs-on: ubuntu-latest steps: - run: echo "Running tests"
deploy: needs: test if: ${{ !failure() && !cancelled() }} runs-on: ubuntu-latest steps: - run: echo "Deploying since tests passed or were skipped"
Step-level conditions
Control step execution based on previous outputs - useful for multi-stage deployments:
steps: - id: check_env run: | echo "status=ready" >> $GITHUB_OUTPUT
- if: ${{ steps.check_env.outputs.status == 'ready' }} run: echo "Environment is ready for deployment"
Key contexts for conditions
github
- Access branch names, event types, commit infoneeds
- Check status of dependent jobssteps
- Read previous step outputs and statusenv
- Use environment variablesjob
- Get info about current jobrunner
- Access runner environment details
Status check functions
success()
- Green light - previous steps passedfailure()
- Red light - something failed upstreamcancelled()
- Someone hit the cancel buttonalways()
- Run regardless of previous status (use carefully!)
Expression syntax
Expressions use ${{ <expression> }}
syntax (optional in if
conditions). Chain conditions with &&
(AND) and ||
(OR):
steps: - if: | github.ref == 'refs/heads/main' && github.event_name == 'push' && success() run: echo "Running production deploy on main branch push"