---
title: "Path filters in GitHub Actions: skip irrelevant CI runs"
description: "Use paths and paths-ignore so expensive workflows skip docs-only or unrelated changes. Add path filters in GitHub Actions, with copyable YAML."
url: https://starsling.dev/best-practices/github-actions/path-filter-workflows
canonicalUrl: https://starsling.dev/best-practices/github-actions/path-filter-workflows
---

# Filter workflows by path in GitHub Actions

Best practice: Trigger Scope. Last updated: 2026-07-06

Add `paths` or `paths-ignore` to expensive workflows so a docs-only or unrelated change doesn't trigger the full test suite.

## Do this

Expensive workflows (E2E, full integration suites) declare a `paths` filter listing the source directories that can actually affect them, or a `paths-ignore` list for docs and markdown. A README change no longer spins up the entire suite.

_Only run when relevant files change_

```yaml
on:
  pull_request:
    paths:
      - "src/**"
      - "package.json"
      - "pnpm-lock.yaml"
      - ".github/workflows/e2e.yml"   # re-run if the workflow itself changes
```

## Avoid this

A docs-only change spins up the full suite, spending wall-clock and runner minutes for nothing.

_Runs on every change, including docs_

```yaml
on:
  pull_request:   # a one-word README fix triggers the full E2E suite
```

## Why it matters

Running an expensive suite on changes that can't affect it is pure waste, both wall-clock the developer waits on and runner-minutes you pay for. Path filters are a high-impact, low-risk trigger fix. The one thing to watch: if a *required* status check is path-filtered, a skipped run never reports its status, and GitHub has no branch-protection setting that treats a missing check as passed, so the PR waits forever. Either don't make the path-filtered workflow a required check, or gate the work with a job-level `if:` condition instead of a workflow-level `paths` filter: GitHub reports a job skipped by a conditional as `Success`, which satisfies the required check, whereas a skipped workflow reports nothing at all.

## When to use

**Use it when:** Workflows with several jobs and a clear set of source paths that gate them, especially E2E and integration suites.

**Be careful when:** Be careful path-filtering a *required* status check: a filtered-out workflow never reports, and GitHub can't treat a missing check as satisfied, so the PR stays blocked. Prefer path-filtering non-required expensive workflows. If the check must stay required, gate the work with a job-level `if:` condition instead: a job skipped by a conditional reports `Success` and satisfies the check, unlike a workflow skipped by `paths`.

## Verify on your repo

Hand this prompt to your coding agent to audit and fix this practice in your own repo:

Inspect this repo's .github/workflows for expensive workflows (E2E, integration suites) that trigger on every change with no path scoping. For each, look at the `on:` block for `paths:` or `paths-ignore:` and flag multi-job workflows that have neither. Add a `paths` allowlist of the source directories that can actually affect the workflow (include the workflow file itself) so a docs-only change does not spin up the full suite. Important: do not path-filter a *required* status check, since a skipped workflow never reports and blocks the PR forever, so instead gate the expensive work with a job-level `if:` condition (a job skipped by a conditional reports Success). Show me the diff and open a PR rather than applying it blindly.

Prefer to check by hand:

- Look at the `on:` block of each expensive workflow for `paths:` or `paths-ignore:`.
- Flag workflows with several jobs and no path filtering at all.
- For any *required* check, don't path-filter the whole workflow: either drop it from the required list, or gate the expensive work with a job-level `if:` (a job skipped by a conditional reports `Success`), so PRs aren't blocked waiting on a check that never runs.

## FAQ

### Should I use paths or paths-ignore?

`paths` is an allowlist (run only when these change) and is safest for a suite with a well-defined source set. `paths-ignore` is a denylist (skip when only these change) and fits when you mainly want to exclude docs and markdown. Don't set both on the same event.

### Will a path filter break a required status check?

It can. When a workflow is skipped by a `paths` filter, its check context never reports, and branch protection waits for it forever, GitHub has no setting that counts a missing check as passed. The safe fix: don't require a path-filtered workflow, or gate the expensive job with a job-level `if:` condition instead. GitHub reports a job skipped by a conditional as `Success` (which satisfies the required check), whereas a skipped workflow reports nothing.

## More best practices for GitHub Actions

- [Cancel superseded runs with concurrency groups](https://starsling.dev/best-practices/github-actions/cancel-superseded-runs)
- [Build and test only what changed in GitHub Actions](https://starsling.dev/best-practices/github-actions/build-only-affected)
- [All CI best practices](https://starsling.dev/best-practices/github-actions)

## Sources

1. [GitHub Actions - paths / paths-ignore filters](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows)
2. [GitHub - troubleshooting required status checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks)
