With one quality gate per repository, a frontend PR fails because services/api still carries a pre-existing critical — a finding the frontend team can neither fix nor merge past. Components fix this. A component is a named subtree of the repository. It owns a set of paths, has its own thresholds, and posts its own status check, so a PR is only ever blocked by the components it actually touches.

What a component is

Two things: a key (web) and the paths it owns (apps/web, libs/shared). The key selects which quality gate config applies and names the PR status check. The paths decide which findings count and whether the component cares about a given PR at all.
The key alone is not enough. --component web with no resolvable paths selects that component’s gate and status-check name, but it does not scope findings and does not enable the untouched-component skip — both require paths. Always configure paths as well.

Define your components

Paths resolve from the first source that provides them:
1

CLI flags (highest precedence)

tigergate scan --component web --component-path apps/web,libs/shared
Also readable from the environment as TG_COMPONENT and TG_COMPONENT_PATH.
2

A component's own .tigergate.yml

Useful when the component directory should carry its own configuration.
component: web
component_paths:
  - apps/web
  - libs/shared
Note the singular component key alongside component_paths.
3

The platform

Set Component and Component paths on the quality gate under CI/CD → Quality Gates, and every CI job for that component inherits them — no paths repeated in pipeline YAML.
4

Directory-name fallback

If nothing above provides paths and the component key is itself an existing directory, that directory is used. So --component apps/web alone works for the simple case.

How a component knows a PR isn’t its business

The CLI diffs the PR against its base branch and intersects the changed files with the component’s paths. This happens before any scanning. When nothing intersects, the CLI prints Component "api" owns none of the 1 file(s) changed in this PR (services/api) — skipping scan, posts a passing status for that component, creates no scan run, uploads nothing, and exits 0.
PR touches--component web job--component api job
apps/web/** onlyscans, web gate appliesskips, passes
services/api/** onlyskips, passesscans, api gate applies
bothscans, web gate appliesscans, api gate applies
docs or root files onlyskips, passesskips, passes
The base branch is detected from the CI environment — GITHUB_BASE_REF, CI_MERGE_REQUEST_TARGET_BRANCH_NAME, SYSTEM_PULLREQUEST_TARGETBRANCH or BITBUCKET_PR_DESTINATION_BRANCH — falling back to HEAD~1. Detection fails open: when the diff can’t be computed (not a PR build, a shallow clone, no base ref), the component is treated as touched and is scanned. A component is never skipped on a guess.
Check out full history so the diff can be computed — fetch-depth: 0 on GitHub Actions, GIT_DEPTH: 0 on GitLab, depth: full on Bitbucket. Without it every component falls back to scanning.
Pass --skip-untouched=false to scan regardless of the diff. That’s the right setting for a nightly or post-merge job.

What a component run contains

Findings outside the component’s paths are dropped before upload, so the component’s thresholds only ever see code it owns. This covers SAST, quality, secrets, IaC, SBOM packages and SCA vulnerabilities. Details worth knowing:
  • Prefix matching is path-segment aware. apps/web matches apps/web/src/a.ts but not apps/webhooks/x.ts.
  • A single component path also narrows the scanners themselves, so a component scan doesn’t pay for the whole monorepo. Reported paths stay repo-root-relative either way. A path that isn’t a real directory falls back to scanning the repo and relying on the filter, rather than silently scanning nothing.
  • Dependencies that can’t be attributed to a path are kept, not dropped, so a component is never reported as cleaner than it is.
  • Component scoping composes with --scan-scope diff. With both, a finding must be inside the component and in the PR’s changed code to count.
A component run is not a whole-repo picture — it deliberately contains only that component’s findings. Keep one unscoped scan on your default branch (tigergate scan --scan-scope full, no --component) so the dashboard retains the complete inventory.
A shared library can be listed in several components’ paths. Every component that claims it is then gated on its findings.

Status checks and branch protection

Each component posts its own check, so components never overwrite each other’s verdict on the same commit:
ComponentCheck name
none (whole repo)TigerGate Security
webTigerGate Security (web)
apiTigerGate Security (api)
Require the per-component contexts in branch protection rather than the single repo-wide one. Naming works the same way on GitHub, GitLab, Bitbucket and Azure DevOps. Platform-side PR decoration, when enabled, posts as TigerGate / Quality Gate (web).
Do not use on.pull_request.paths (GitHub) or rules:changes (GitLab) to skip component jobs. A required status check whose job never runs leaves the PR pending forever. Let every component job start — the CLI skips the irrelevant ones in seconds and still posts a passing status. That is exactly what --skip-untouched is for, and why it defaults to on.

Which gate judged the build

Configs resolve most-specific-first:
  1. Repository matches and component matches
  2. Repository matches, component blank — the repo-wide gate
  3. Repository blank and component matches — an org-wide rule for that component name
  4. Repository blank, component blank — the Organization Default
A component with no config of its own inherits the repo-wide gate. The CLI logs which config judged the run, for example Quality gate: acme/mono / component web, so an unconfigured component is visible in the build log instead of being a surprise. The component is read from the recorded scan run, not from the request, so a pipeline cannot point itself at a laxer component’s thresholds.

Wiring your pipeline

One CI job per component. Only three things matter, on any platform:
  1. One job per component, each passing --component <key> — that is what produces a separate gate and a separate status check.
  2. Full git history, so the base-branch diff can be computed.
  3. Independent failure, so one component’s failing gate does not cancel the rest.
Ready-to-copy recipes for GitHub Actions, GitLab CI, Bitbucket Pipelines, Jenkins, Azure Pipelines / TFS, CircleCI, AWS CodeBuild, Google Cloud Build, Drone CI, Travis CI, Buildkite, TeamCity, Tekton and any generic Docker runner are in CI/CD integration. Component paths can live in the dashboard instead of the pipeline: set Component paths on each component’s gate and the CI job needs only --component <key>, so re-scoping a component becomes a UI edit. The component key itself must stay in the pipeline — the platform can say what a component owns, but only the job knows which component it is. For threshold semantics — per-severity limits, new-code mode, license blocking and coverage floors — see Quality gates.