What is an Actuator health group in Spring Boot, and how do you create one that exposes only a subset of health indicators?
answer
- group.<name>.include / .exclude
- path /actuator/health/<name>
- exclude beats include
- include=* means all
- status from group members only
basics
~10 sA health group bundles a chosen subset of health indicators under a named sub-endpoint. You configure it with management.endpoint.health.group.<name>.include=<indicators>, then read it at /actuator/health/<name>.
solid answer
~40 sBy default /actuator/health aggregates every registered health indicator (db, diskSpace, ping, etc.) into one overall status. A health group lets you carve out a named subset that answers at its own path, /actuator/health/<name>. You declare it purely in properties: `management.endpoint.health.group.custom.include=db,diskSpace` includes those contributors, and `.exclude` removes some (exclude wins over include). `include=*` takes everything then you exclude a few. The group computes its own aggregated status from only its members, so a failing indicator outside the group won't drag the group DOWN. This is the basis for Kubernetes liveness/readiness probes, where each probe should watch a different, targeted set of checks rather than the whole application.
code
yaml · 15 linesmanagement:
endpoints:
web:
exposure:
include: health
endpoint:
health:
group:
# /actuator/health/custom -> only these two indicators
custom:
include: db, diskSpace
# /actuator/health/light -> everything except the expensive db check
light:
include: "*"
exclude: dbgo deeper
Know the property shape (group.<name>.include) and the resulting path /actuator/health/<name>.
Understand exclude-beats-include, include=*, and that status is computed from group members only.
Frame groups as the mechanism enabling distinct K8s liveness/readiness probes over targeted indicator subsets.
Reason about isolation guarantees and the operational risk of silently-ignored bad ids masking a non-functioning probe.
## What the health endpoint does by default Spring Boot Actuator's `/actuator/health` endpoint is backed by a `HealthEndpoint` that aggregates every `HealthContributor` bean the app registers — a `DataSourceHealthIndicator` (id `db`), `DiskSpaceHealthIndicator` (`diskSpace`), `PingHealthIndicator` (`ping`), plus any custom ones. It combines their individual statuses into ONE overall `Status` (UP, DOWN, OUT_OF_SERVICE, UNKNOWN) using a `StatusAggregator` — by default the worst status wins (DOWN beats UP). ## The problem groups solve One combined status is too coarse for real deployments. A Kubernetes **liveness** probe should only fail when the app is unrecoverable (restart me), while a **readiness** probe should fail when the app temporarily can't serve traffic (stop routing to me). If both read the same aggregated `/actuator/health`, a flaky external dependency could make Kubernetes *restart* a perfectly alive pod. Groups fix this by letting you expose different, targeted subsets. ## Creating a group Groups are pure configuration — no code, no beans. In `application.yml` / `application.properties`: ``` management.endpoint.health.group.custom.include=db,diskSpace ``` That creates a group named `custom`, reachable at `/actuator/health/custom`. The `<name>` is arbitrary; the value is a comma-separated list of **health indicator ids** (the id is the bean name minus the `HealthIndicator` suffix — `DataSourceHealthIndicator` → `db`). - `include` — the members to add. `*` means "all indicators". - `exclude` — members to remove; **exclude takes precedence over include**, so `include=*` + `exclude=db` = everything except `db`. ## Status is computed from group members only Each group aggregates the status of just its own members. If `diskSpace` is DOWN but it's not in your group, the group stays UP. This isolation is the whole point. ## Gotchas - The group name becomes a URL path segment, so keep it URL-safe (lowercase, no spaces). - Referencing an indicator id that doesn't exist is silently ignored — a typo like `dataSource` instead of `db` means that check simply never runs, so the group can look green while watching nothing. Verify ids by hitting `/actuator/health` with details on. - The health endpoint must itself be exposed (`management.endpoints.web.exposure.include=health`) for any group to be reachable. - Groups are additive to the main endpoint — `/actuator/health` still exists and still aggregates everything. ## When to use Any time different consumers (K8s liveness vs readiness, a load balancer, an internal dashboard) need to watch different slices of health, or when you want a lightweight probe that doesn't touch expensive downstream checks.
- If an indicator id in your include list is misspelled, what happens?It's silently ignored — no error. The group simply won't include that check, so it can report UP while watching fewer indicators than you think. Always verify ids against /actuator/health details.
- Does creating a group remove indicators from the main /actuator/health?No. Groups are additional named sub-endpoints. /actuator/health still aggregates all indicators as before; groups just expose extra, filtered views.
saying these in an interview costs you the question
- Thinking a group replaces the main /actuator/health endpoint
- Believing include takes precedence over exclude (it's the reverse)
- Assuming a group aggregates ALL indicators rather than only its members