skip to content

Health Indicators & Probes

Health checks in depth: writing indicators, the built-in ones, how statuses aggregate into a response code, health groups, and Kubernetes liveness and readiness. Interviewers ask because a badly designed health check will restart your service during a dependency blip.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

26

What are Spring Boot's built-in health indicators, and which ones does Actuator auto-register out of the box?

level: juniorimportance: must knowfreq 70%

answer

  1. ping = always UP
  2. diskSpace default 10MB threshold
  3. db = DataSourceHealthIndicator
  4. show-details defaults to never
  5. overall = worst status

basics

~10 s

Built-in health indicators are checks Actuator adds automatically to the /actuator/health endpoint. Common ones: PingHealthIndicator (always up), DiskSpaceHealthIndicator (free disk), DataSourceHealthIndicator (database), and RedisHealthIndicator when those libraries are present.

solid answer

~30 s

Spring Boot Actuator auto-configures a set of HealthIndicator beans that report component health at /actuator/health. Always present is PingHealthIndicator (a trivial 'app is alive' check) and DiskSpaceHealthIndicator (fails when free space drops below a threshold). Others are conditional on what's on the classpath and configured: DataSourceHealthIndicator (registered under the name 'db') runs a validation query against your DataSource; RedisHealthIndicator issues an INFO command to Redis. Each contributes a status (UP/DOWN/etc.) plus optional details. The overall endpoint status is the worst of all contributors. By default the endpoint shows only the top-level status; you enable per-component detail with management.endpoint.health.show-details=always (or when-authorized).

code

java · 14 lines
java
// application.properties
// Reveal per-component health in the endpoint body
// management.endpoint.health.show-details=always

// Example /actuator/health response with details on:
// {
//   "status": "UP",
//   "components": {
//     "db":        { "status": "UP", "details": { "database": "PostgreSQL", "validationQuery": "isValid()" } },
//     "diskSpace": { "status": "UP", "details": { "total": 500107862016, "free": 250053931008, "threshold": 10485760 } },
//     "ping":      { "status": "UP" },
//     "redis":     { "status": "UP", "details": { "version": "7.2.4" } }
//   }
// }

go deeper

for a junior

Know the four named indicators exist and that /health aggregates them; know show-details must be enabled to see components.

for a middle

Explain conditional registration by classpath, the naming scheme (db, diskSpace, ping, redis), and worst-status aggregation.

for a senior

Discuss show-details security tradeoffs (when-authorized), HTTP status mapping to 503, and how indicators feed probes.

for a principal

Frame health as an operational contract for orchestrators/LBs; reason about which checks belong in liveness vs readiness and blast radius of a DOWN dependency.

## What a health indicator is Spring Boot **Actuator** exposes an operational endpoint at `/actuator/health`. Its job is to answer 'is this application and its dependencies healthy?' The endpoint aggregates many **HealthIndicator** beans, each of which checks one thing (the database, disk, Redis, etc.) and returns a **Health** object carrying a **Status** (`UP`, `DOWN`, `OUT_OF_SERVICE`, `UNKNOWN`) plus an optional map of details. ## Which ones are auto-registered Actuator auto-configures indicators based on what's on the classpath (this is the whole point of Spring Boot auto-configuration — beans appear only when their supporting libraries and beans exist): - **PingHealthIndicator** — always registered. It does nothing but return `UP`. It's a cheap 'the web layer and Actuator are responding' signal. - **DiskSpaceHealthIndicator** — always registered. Checks free space on a configured path (default: the app's working directory) against a threshold (default **10 MB**). Returns `DOWN` when free space is below the threshold. - **DataSourceHealthIndicator** — registered when a `javax.sql.DataSource` bean exists. Its contributor name is **`db`**. It borrows a connection and runs a driver-appropriate validation query (e.g. `SELECT 1`). - **RedisHealthIndicator** — registered when Spring Data Redis and a `RedisConnectionFactory` are present. Issues Redis `INFO` and reports the server version. - Many more follow the same pattern: `MongoHealthIndicator`, `CassandraHealthIndicator`, `ElasticsearchHealthIndicator`, `RabbitHealthIndicator`, `MailHealthIndicator`, `LivenessStateHealthIndicator`/`ReadinessStateHealthIndicator`, etc. ## Naming Each indicator is registered under a **name** derived from its bean name with the `HealthIndicator` suffix stripped — `ping`, `diskSpace`, `db`, `redis`. That name is both the JSON key under `components` and the key used in the toggle properties (`management.health.<name>.enabled`). ## Seeing the details By default `/actuator/health` returns only `{"status":"UP"}` — no component breakdown — because `management.endpoint.health.show-details` defaults to `never`. Set it to `always` (or `when-authorized`, which only reveals details to authenticated/authorized users) to see per-indicator status and details. ## Overall status The endpoint's aggregate status is the **worst** individual status, ordered by a `StatusAggregator` (default worst→best: `DOWN`, `OUT_OF_SERVICE`, `UP`, `UNKNOWN`). A single `DOWN` component makes the whole endpoint `DOWN`, which by default maps to HTTP **503**. ## When to use Health indicators feed load balancers, container orchestrators (Kubernetes liveness/readiness probes), and monitoring. Understanding which are auto-registered tells you what your `/health` will report before you write any custom code.

  • Why does /actuator/health show only {"status":"UP"} by default with no components?
    Because management.endpoint.health.show-details defaults to 'never' to avoid leaking infrastructure detail to anonymous callers. Set it to 'always' or 'when-authorized' to expose the component breakdown.
  • If the database is down but ping is up, what does the overall endpoint report?
    DOWN. The aggregate status is the worst of all contributors, so one DOWN component (db) makes the whole endpoint DOWN, mapping to HTTP 503 by default.

saying these in an interview costs you the question

  • Thinking all health indicators (Mongo, Redis, DB) are always present regardless of classpath
  • Believing /actuator/health shows component details by default
  • Assuming overall status is 'UP' unless every check fails (it's actually the worst single status)

context

open as a page

What is an Actuator health group in Spring Boot, and how do you create one that exposes only a subset of health indicators?

level: juniorimportance: must knowfreq 35%

basics

~10 s

A 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>.

open as a page

What is a Spring Boot HealthIndicator and how do you implement one that reports UP or DOWN?

level: juniorimportance: must knowfreq 70%

basics

~10 s

A HealthIndicator is a bean that reports the health of one dependency. You implement the health() method to return Health.up() when things work or Health.down() when they don't, and Spring exposes it at /actuator/health.

open as a page

What is the difference between the liveness and readiness probes exposed by Spring Boot Actuator, and what does Kubernetes do with each?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Liveness says the app is running and healthy; if it fails, Kubernetes restarts the pod. Readiness says the app can accept traffic right now; if it fails, Kubernetes stops routing requests to it but does not restart.

open as a page

In Spring Boot Actuator, what does management.endpoint.health.show-details control, and what are its three possible values?

level: juniorimportance: must knowfreq 70%

basics

~10 s

It controls how much detail /actuator/health shows. Values: never (default, only overall status), when-authorized (details shown to logged-in/authorized users), and always (details shown to everyone).

open as a page

How do you disable one built-in health indicator versus all of them, using the management.health.* properties?

level: middleimportance: must knowfreq 55%

basics

~10 s

Disable a single indicator with management.health.<name>.enabled=false (e.g. management.health.db.enabled=false, management.health.redis.enabled=false). Disable all built-ins at once with management.health.defaults.enabled=false, then selectively re-enable the ones you want.

open as a page

How do you programmatically flip the readiness (or liveness) probe to DOWN at runtime in Spring Boot?

level: seniorimportance: must knowfreq 50%

basics

~10 s

Publish an AvailabilityChangeEvent via the ApplicationEventPublisher, e.g. AvailabilityChangeEvent.publish(publisher, this, ReadinessState.REFUSING_TRAFFIC). Spring updates ApplicationAvailability and the probe endpoint immediately reflects the new state.

open as a page

How does DiskSpaceHealthIndicator decide UP vs DOWN, and how do you configure its threshold and path?

level: middleimportance: should knowfreq 45%

basics

~10 s

It reports the free space on a directory and returns DOWN when free space falls below a threshold (default 10 MB). You change it with management.health.diskspace.threshold and management.health.diskspace.path.

open as a page

How do you control detail visibility (show-details / show-components) independently for a single health group?

level: middleimportance: should knowfreq 22%

basics

~10 s

Each group accepts its own management.endpoint.health.group.<name>.show-details and .show-components set to never, when-authorized, or always. These override the global management.endpoint.health.show-details for that group only.

open as a page

What does AbstractHealthIndicator give you over implementing HealthIndicator directly, and how does doHealthCheck work?

level: middleimportance: should knowfreq 55%

basics

~20 s

AbstractHealthIndicator is a base class that implements health() for you and wraps your check in a try/catch. You override doHealthCheck(Health.Builder), and if it throws, the base class automatically sets status DOWN and records the exception.

open as a page

A custom HealthIndicator returns Health.status("DEGRADED"). Explain how that status affects the endpoint's overall status and HTTP code, and how to surface the details.

level: middleimportance: should knowfreq 45%

basics

~20 s

A custom status like DEGRADED is unknown to Spring's default aggregator, so it's treated as least severe and won't drag the endpoint down, and by default it maps to HTTP 200. To make it meaningful you must configure the status order and its HTTP mapping, and set show-details to see the details.

open as a page

How do you read the current liveness/readiness state programmatically in Spring Boot, and what are the possible state values?

level: middleimportance: should knowfreq 45%

basics

~10 s

Inject the ApplicationAvailability bean and call getLivenessState() or getReadinessState(). Liveness is CORRECT or BROKEN; readiness is ACCEPTING_TRAFFIC or REFUSING_TRAFFIC. Both implement the AvailabilityState interface.

open as a page

What is the HttpCodeStatusMapper, and what HTTP status codes does /actuator/health return by default for each health status?

level: middleimportance: should knowfreq 50%

basics

~10 s

The HttpCodeStatusMapper maps a health Status to an HTTP status code. By default DOWN and OUT_OF_SERVICE return 503 (Service Unavailable); UP and UNKNOWN return 200 OK. You customize it via management.endpoint.health.status.http-mapping.

open as a page

How does Spring Boot compute the single overall health status from many contributors, and how is the severity ordering configured?

level: middleimportance: should knowfreq 55%

basics

~10 s

A StatusAggregator (default SimpleStatusAggregator) picks the most severe status among all contributors. The default order (most to least severe) is DOWN, OUT_OF_SERVICE, UP, UNKNOWN. You can override it with management.endpoint.health.status.order.

open as a page

How does DataSourceHealthIndicator actually verify the database, and what happens with multiple DataSources?

level: seniorimportance: should knowfreq 40%

basics

~20 s

It borrows a connection from the pool and runs a lightweight validation query (a driver-specific query like SELECT 1, or Connection.isValid() if none is known). Success is UP, an exception is DOWN. With several DataSources it groups them into a composite.

open as a page

How does RedisHealthIndicator work, and how does one built-in indicator's status roll up into the overall /health status and HTTP code?

level: seniorimportance: should knowfreq 35%

basics

~20 s

RedisHealthIndicator asks Redis for its INFO (server version) via the connection factory; success is UP, a connection error is DOWN. The overall /health status is the worst of all indicators, and DOWN/OUT_OF_SERVICE map to HTTP 503 by default.

open as a page

How can you expose a single health group on the main server port (not the management port) so a Kubernetes probe can reach it, and why would you?

level: seniorimportance: should knowfreq 14%

basics

~10 s

Set management.endpoint.health.group.<name>.additional-path=server:/healthz. That serves the group on the main application port at /healthz, in addition to its normal /actuator/health/<name> path.

open as a page

How do you make a health group return a custom HTTP status code (e.g. map OUT_OF_SERVICE to 503) independently of the main health endpoint?

level: seniorimportance: should knowfreq 18%

basics

~10 s

Use management.endpoint.health.group.<name>.status.http-mapping.<status>=<code>, e.g. map out-of-service to 503. This overrides the global status-to-HTTP mapping for that one group.

open as a page

How do HealthContributor and CompositeHealthContributor let you group and nest health checks?

level: seniorimportance: should knowfreq 40%

basics

~20 s

HealthContributor is the marker interface that HealthIndicator implements. A CompositeHealthContributor bundles several named contributors under one parent, so the endpoint shows a nested tree — for example one "externalApis" node with a child per API.

open as a page

How do Spring Boot's availability states behave across the application lifecycle, and how does this interact with graceful shutdown in Kubernetes?

level: seniorimportance: should knowfreq 35%

basics

~20 s

At startup liveness becomes CORRECT early; readiness becomes ACCEPTING_TRAFFIC only when the app is fully ready. On shutdown Spring flips readiness to REFUSING_TRAFFIC so Kubernetes drains traffic before the process stops, which pairs with graceful shutdown.

open as a page

How do you register a custom health Status (e.g. FATAL) and wire it correctly into severity ordering and HTTP mapping?

level: seniorimportance: should knowfreq 35%

basics

~10 s

Create a new Status("FATAL") and return it from a HealthIndicator via Health.status(...). Then add FATAL to management.endpoint.health.status.order so it's ranked correctly, and to status.http-mapping so it returns the right HTTP code.

open as a page

Where do the built-in liveness and readiness health groups come from, and how do they connect to Spring's ApplicationAvailability?

level: principalimportance: should knowfreq 16%

basics

~10 s

When probes are enabled (auto on Kubernetes), Spring Boot auto-creates 'liveness' and 'readiness' groups exposing LivenessStateHealthIndicator and ReadinessStateHealthIndicator. These read the app's LivenessState/ReadinessState via ApplicationAvailability, which you update by publishing AvailabilityChangeEvents.

open as a page

How do reactive health checks differ from blocking ones, and what happens to a blocking HealthIndicator in a WebFlux app?

level: principalimportance: should knowfreq 35%

basics

~20 s

In a reactive (WebFlux) app you implement ReactiveHealthIndicator, whose health() returns Mono<Health> instead of a blocking Health. Existing blocking HealthIndicators still work — Spring adapts them and runs their code on a bounded elastic scheduler so they don't block the event loop.

open as a page

Architecturally, how does Actuator wire up these built-in indicators, and how does HealthContributor relate to HealthIndicator and readiness/liveness probes?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Each built-in indicator has its own auto-configuration (e.g. DataSourceHealthContributorAutoConfiguration) that conditionally registers a HealthContributor. HealthIndicator is a single HealthContributor; a CompositeHealthContributor groups several. Kubernetes probes are served via health groups (liveness/readiness) built on the same registry.

open as a page

How are the liveness and readiness health groups composed, and how would you add your own health checks or a custom availability dimension into a probe group?

level: principalimportance: nice to knowfreq 20%

basics

~10 s

The probes are Actuator health groups: 'liveness' includes livenessState and 'readiness' includes readinessState. You can override group membership with management.endpoint.health.group.<name>.include to add other indicators, and set per-group status mappings and roles.

open as a page

Design a production health endpoint strategy covering aggregation severity, HTTP mapping for probes, and safe detail exposure. What are the trade-offs and pitfalls?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Keep show-details at never or when-authorized to avoid leaking infra data; let DOWN/OUT_OF_SERVICE map to 503 so load balancers and probes react; configure status.order and http-mapping consistently for any custom status; and separate liveness from readiness so transient dependency failures don't kill pods.

open as a page