Home/Learn/Spring Boot/Health Indicators

Health Indicators

Intermediate
Actuator & Ops

Built-in health indicators report the status of DB, Kafka, Redis, and disk; custom indicators implement HealthIndicator and are aggregated into a composite UP/DOWN.

Overview

Spring Boot Actuator's /actuator/health endpoint aggregates the health of all registered HealthIndicator beans into a single composite status (UP, DOWN, OUT_OF_SERVICE, UNKNOWN). Built-in indicators cover the most common dependencies: DataSource (ping query), Kafka (AdminClient describe cluster), Redis (PING), RabbitMQ (connection check), and disk space. Custom indicators let you check business-critical dependencies (external APIs, license servers, downstream services). Kubernetes uses /actuator/health/liveness and /actuator/health/readiness as separate probes: liveness for crash detection, readiness to control traffic admission. Exposing sensitive health details requires the management.endpoint.health.show-details=always setting with proper security controls.

Actuator health endpoint and configuration

Enable and expose the health endpoint; configure detail visibility and Kubernetes liveness/readiness groups.

Properties + YAML — health endpoint + K8s probes
# application.properties
management.endpoint.health.enabled=true
management.endpoints.web.exposure.include=health,info,metrics,prometheus

# Show full health details (component breakdown)
# Restrict to ADMIN role in production; "when_authorized" uses security
management.endpoint.health.show-details=always
# Or: only show details for authenticated ADMIN users
# management.endpoint.health.show-details=when_authorized

# Kubernetes liveness and readiness probes
management.endpoint.health.probes.enabled=true
management.health.livenessstate.enabled=true
management.health.readinessstate.enabled=true

# /actuator/health/liveness  → {status: "LIVE" or "BROKEN"}
# /actuator/health/readiness → {status: "ACCEPTING_TRAFFIC" or "REFUSING_TRAFFIC"}

# Kubernetes probe config (deployment.yaml)
# livenessProbe:
#   httpGet: { path: /actuator/health/liveness, port: 8080 }
#   initialDelaySeconds: 30
#   periodSeconds: 10
# readinessProbe:
#   httpGet: { path: /actuator/health/readiness, port: 8080 }
#   initialDelaySeconds: 10
#   periodSeconds: 5

Custom HealthIndicator

Implement HealthIndicator to add a business-specific health check. The component name becomes the key in the health response.

Java — custom HealthIndicator
@Component
public class PaymentGatewayHealthIndicator implements HealthIndicator {

    private final PaymentGatewayClient client;

    @Override
    public Health health() {
        try {
            PingResponse response = client.ping();

            if (response.isOk()) {
                return Health.up()
                    .withDetail("latency_ms", response.getLatencyMs())
                    .withDetail("version", response.getApiVersion())
                    .build();
            } else {
                return Health.down()
                    .withDetail("reason", "Ping returned: " + response.getStatus())
                    .build();
            }
        } catch (Exception e) {
            return Health.down()
                .withException(e)
                .withDetail("url", client.getBaseUrl())
                .build();
        }
    }
}

// Health response at /actuator/health:
// {
//   "status": "UP",
//   "components": {
//     "paymentGateway": { "status": "UP", "details": {"latency_ms": 42} },
//     "db":             { "status": "UP" },
//     "redis":          { "status": "UP" }
//   }
// }

ReactiveHealthIndicator and health groups

For WebFlux apps use ReactiveHealthIndicator. Health groups let you include/exclude specific indicators per probe (liveness should not include DB).

Properties + Java — health groups + ReactiveHealthIndicator
# Health groups: liveness should only check in-process state (not DB)
# If DB is down, pod is not "crashed" — readiness handles that
management.endpoint.health.group.liveness.include=livenessState
management.endpoint.health.group.readiness.include=readinessState,db,redis,kafka

# Custom group for internal monitoring (show all)
management.endpoint.health.group.internal.include=*
management.endpoint.health.group.internal.show-details=always

// ReactiveHealthIndicator for WebFlux
@Component
public class ExternalApiHealthIndicator implements ReactiveHealthIndicator {

    private final WebClient webClient;

    @Override
    public Mono<Health> health() {
        return webClient.get()
            .uri("/health")
            .retrieve()
            .bodyToMono(String.class)
            .map(body -> Health.up().withDetail("response", body).build())
            .timeout(Duration.ofSeconds(2))
            .onErrorReturn(Health.down()
                .withDetail("reason", "Timeout or connection refused").build());
    }
}

Key Points to Remember

  • 1Liveness probe: is the JVM alive? Should only check in-process state. Down → pod restarts.
  • 2Readiness probe: can the pod serve traffic? Should check DB, Redis, Kafka. Down → pod removed from LB.
  • 3Never include database in liveness — a slow DB query would restart healthy pods.
  • 4show-details=when_authorized requires the caller to be authenticated; use this in production to hide internals.
  • 5Custom HealthIndicators are auto-discovered as Spring beans; name the component to control the JSON key.
  • 6Health status aggregation: one DOWN component makes the composite status DOWN unless explicitly excluded.

Interview Questions

Sign in to ask Aria
1

What is the difference between a liveness probe and a readiness probe in Kubernetes?

EasyAmazon
2

Why should you NOT include database health in the liveness probe?

MediumNetflix
3

How do you implement a custom health indicator that checks an external API?

MediumGoogle
4

How would you configure separate health groups for liveness and readiness in Spring Boot?

MediumUber
5

What happens to the composite health status when one HealthIndicator returns DOWN?

EasyShopify

Ask Aria about Health Indicators

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…