Skip to content

Domains

Domains are logical groupings of packages with shared coverage requirements. They allow you to enforce different coverage thresholds for different parts of your codebase.

Each domain has a name, match patterns, and a minimum coverage threshold:

policy:
domains:
- name: core
match: ["./internal/core/..."]
min: 85
- name: api
match: ["./internal/api/..."]
min: 80

Match patterns use Go’s package path syntax:

PatternMatches
./internal/core/...All packages under internal/core/
./cmd/...All packages under cmd/
./pkg/utilsOnly the pkg/utils package
./internal/*/serviceservice packages one level deep
domains:
# Match all subpackages
- name: core
match: ["./internal/core/..."]
min: 85
# Match multiple paths
- name: api
match:
- "./internal/api/..."
- "./internal/handlers/..."
min: 80
# Match specific packages
- name: utils
match:
- "./pkg/utils"
- "./pkg/helpers"
min: 70

Use the exclude field to skip files from coverage analysis:

exclude:
- "**/generated/**"
- "**/mocks/**"
- "**/*_test.go"
- "**/testdata/**"
PatternMatches
**/generated/**Any file under a generated directory
**/*_mock.goAny file ending in _mock.go
internal/legacy/*Files directly in internal/legacy/

coverctl can automatically detect domains from your project structure:

Terminal window
# Preview detected domains
coverctl detect --dry-run
# Write config
coverctl detect
DirectoryDetected Domain
cmd/CLI entry points
internal/core/Core business logic
internal/domain/Domain layer
internal/application/Application services
internal/infrastructure/Infrastructure adapters
internal/api/API layer
pkg/Public packages

Directories named generated, mocks, testdata, or vendor are automatically excluded.

When a file matches multiple domains, it’s assigned to the first matching domain. Order your domains from most specific to least specific:

domains:
# More specific first
- name: core-critical
match: ["./internal/core/critical/..."]
min: 95
# Less specific second
- name: core
match: ["./internal/core/..."]
min: 85

With annotations.enabled: true, you can override domain assignment in code:

// coverctl:domain=critical
package validator
func Validate() error {
// This file belongs to "critical" domain
}
// coverctl:ignore
package generated
// This file is excluded from coverage
  1. Start with auto-detection: Use coverctl detect --dry-run to see suggested domains
  2. Group by criticality: Higher thresholds for core business logic
  3. Use meaningful names: Domain names appear in reports
  4. Keep excludes minimal: Only exclude truly non-testable code
  5. Review overlaps: Check for unintended domain assignments