# SonarQube sonar.inclusions and sonar.exclusions: combine scope patterns without silently scanning nothing
Use this skill when a SonarQube analysis keeps scanning files you tried to include or exclude: test projects still appear after setting exclusions, an inclusion of a folder changes nothing, or combining `sonar.inclusions` with `sonar.exclusions` in an Azure DevOps pipeline produces results that ignore both settings.
## The core model
Inclusions and exclusions compose. Inclusions define the initial file set, exclusions subtract from it. Both are comma-separated lists of Ant-style path patterns, matched relative to the project base directory. Every mistake in this skill comes from treating one of those two facts loosely.
## Write patterns, not paths
A bare folder path matches nothing. This is the single most common failure:
- Wrong: `sonar.inclusions=Repo/Folder 1` — matches zero files, analysis scope silently unchanged.
- Right: `sonar.inclusions=Repo/Folder 1/**/*` — matches everything under that folder.
The `**` wildcard crosses directory boundaries; `*` does not. Any inclusion that names a directory must end in `/**/*` or name files explicitly.
## Anchor patterns correctly
A pattern without a `**/` prefix only matches at the base directory root:
- `Test*.cs` matches test files sitting at the repo root and nothing else.
- `**/Test*.cs` matches test files in any subfolder, which is almost always what you want.
- `**/AssemblyInfo.cs` and `**/*.xml` are correct as written.
- Avoid a leading slash (`/*.bin`). Patterns are already relative to the base directory; a leading slash anchors oddly and usually matches nothing. Use `**/*.bin` instead.
Spaces inside path segments are fine, but remember the list is comma-separated: never put a comma inside a pattern, and quote the whole value in YAML or pipeline variables so the space survives.
## Property names are lowercase and scope-specific
The property names are case-sensitive: `sonar.inclusions` and `sonar.exclusions`, all lowercase. Capitalized variants are silently ignored.
Then the naming trap that causes most "exclusions don't work" reports: similarly named properties control different scopes.
- `sonar.exclusions` — main source files.
- `sonar.test.exclusions` — test files.
- `sonar.coverage.exclusions` — coverage calculation only; the files are still analyzed for issues.
- `sonar.cpd.exclusions` — duplication detection only.
- `sonar.test.inclusions` — which files count as tests (pairs with `sonar.tests`).
If test projects still show up in your overview after setting `sonar.exclusions`, you probably need `sonar.test.exclusions` instead — or as well. Excluding a file from coverage does not exclude it from analysis.
## Combining both in an Azure DevOps pipeline
Pass them as scanner properties on the analysis step, for example:
```
-Dsonar.inclusions="Repo/Folder 1/**/*" -Dsonar.exclusions="**/AssemblyInfo.cs,**/*.xml,**/Test*.cs,**/*.bin"
```
Or set them in `sonar-project.properties` checked into the repo so every pipeline run inherits them. You do not need to enumerate folders one by one: one inclusion pattern for the folder plus exclusion patterns for the noise inside it is the intended combination.
## Quick checklist
1. Every inclusion that names a directory ends in `/**/*`.
2. Every filename pattern that should match in subfolders starts with `**/`.
3. No leading slashes on any pattern.
4. Property names are lowercase `sonar.inclusions` / `sonar.exclusions`.
5. Test files are handled with `sonar.test.exclusions`, not `sonar.exclusions`.
6. Coverage-only noise uses `sonar.coverage.exclusions` so issues are still reported.
7. After changing scope, confirm the file count on the project's overview moved in the expected direction before trusting the numbers.