Understanding Conditional Execution for Jobs and Steps
if: is used to control whether a step or job should run.
It is evaluated before the job or step starts.
Syntax:
if: ${{ condition }}
If the condition is true → it runs If the condition is false → it is skipped
Workflows often require decisions such as:
- Deploy only from main branch
- Skip deployment for feature branches
- Run tests only on pull requests
- Run jobs only when a tag is pushed
- Run steps only if previous step succeeded
- Skip CI if commit message contains skip-ci
if: expressions help create smart CI/CD pipelines.
name: Branch Based Deployment
on:
push:
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building application"
deploy:
runs-on: ubuntu-latest
needs: build
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- run: echo "Deploying to production"
- Push to main → build + deploy
- Push to dev or feature → only build (deploy skipped)
if: ${{ github.ref == 'refs/heads/main' }}
if: ${{ github.ref == 'refs/heads/dev' }}
if: ${{ startsWith(github.ref, 'refs/heads/feature/') }}
if: ${{ startsWith(github.ref, 'refs/tags/') }}
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.ref != 'refs/heads/main' }}
if: ${{ github.event_name == 'push' }}
if: ${{ success() }}
if: ${{ failure() }}
if: ${{ contains(github.event.head_commit.message, 'build') }}
if: ${{ !contains(github.event.head_commit.message, 'skip-ci') }}
if: ${{ secrets.PROD_TOKEN != '' }}
name: Full Deployment Pipeline
on:
push:
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building application"
test:
runs-on: ubuntu-latest
needs: build
steps:
- run: echo "Running tests"
deploy:
runs-on: ubuntu-latest
needs: test
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- run: echo "Deploying to production"
- main branch: build → test → deploy
- dev branch: build → test
- feature branch: build → test
Deployment runs only on main.
- Use
if:to control when jobs and steps run - Use
github.refto detect branch - Use
github.event_nameto detect event type - Use string functions like
startsWithandcontains - Use
success()andfailure()for job status - Use branch-based conditions for real deployments