Skip to content

Configure 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:

Pattern Matches
./internal/core/... All packages under internal/core/
./cmd/... All packages under cmd/
./pkg/utils Only the pkg/utils package
./internal/*/service service 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/**"
Pattern Matches
**/generated/** Any file under a generated directory
**/*_mock.go Any 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
Directory Detected 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