Course topics

By WebNest Studio Engineering Team

Spring Boot Tutorial

Spring Boot Actuator

Once an application is running in production, you need visibility into its health, performance, and internal state without attaching a debugger. Spring Boot Actuator adds a set of production-ready HTTP endpoints — health checks, metrics, environment details, and more — with almost no configuration required beyond adding the starter.

Adding Actuator and the /actuator/health Endpoint

Adding spring-boot-starter-actuator exposes a base /actuator endpoint listing available sub-endpoints. The most commonly used one, /actuator/health, reports whether the application (and its key dependencies — database, disk space, message brokers) is UP or DOWN, which is exactly what load balancers and orchestration platforms like Kubernetes poll to decide whether an instance should keep receiving traffic.

Metrics with /actuator/metrics

/actuator/metrics exposes a catalog of runtime metrics — JVM memory usage, garbage collection pauses, HTTP request counts and latencies, thread pool statistics, and datasource connection pool usage. Requesting a specific metric name (e.g. /actuator/metrics/http.server.requests) returns detailed measurements for that metric. Actuator integrates with Micrometer, which can export the same metrics to Prometheus, Datadog, or other monitoring backends.

Controlling Exposure

Out of the box, only /actuator/health is exposed over HTTP. Every other endpoint, /actuator/info included, returns 404 until you opt in. That default exists because most endpoints (env, beans, mappings, threaddump, heapdump) reveal internal detail that should never be public. You choose what to expose with management.endpoints.web.exposure.include, which takes a comma-separated list of endpoint IDs. Anything sensitive should also sit behind Spring Security, and ideally on a separate management port that is not reachable from the internet.

How Much Detail /actuator/health Shows

management.endpoint.health.show-details decides whether the health response includes the per-component breakdown:

  • never (the default): only the overall status, for example {"status":"UP"}.
  • when-authorized: the components appear only for an authenticated user with the right role. Without Spring Security nobody is authorized, so the response still shows only the status.
  • always: everyone sees every component and its details, such as the database type and the free disk space.

Adding Your Own Health Check

The built-in checks cover the database, disk space and message brokers, but not the services your application depends on, such as a payment provider. Implement HealthIndicator (in Spring Boot 4 it lives in org.springframework.boot.health.contributor) and register it as a bean. Spring Boot names the component after the bean, minus the "HealthIndicator" suffix, so PaymentServiceHealthIndicator appears as paymentService and can be queried on its own at /actuator/health/paymentService. When any component reports DOWN, the overall status becomes DOWN and the endpoint answers with HTTP 503, so a load balancer stops sending traffic to that instance.

Recording Business Metrics

JVM and HTTP metrics come for free, but the numbers a team actually watches are usually business events: orders placed, payments failed, emails sent. Inject Micrometer's MeterRegistry, register a Counter (or a Timer for durations), and increment it in your code. The metric then appears under /actuator/metrics/<name>, and Micrometer can export it to Prometheus or another monitoring backend without any further changes.

When to Use Which Endpoint

  • health: always on. Load balancers, Kubernetes probes and uptime monitors call it.
  • info: expose it when you want a quick way to see which version and build is deployed.
  • metrics or prometheus: expose one of them to whatever collects your metrics, but not to the public internet.
  • env, beans, mappings, loggers, threaddump: debugging tools. Enable them locally or behind authentication, never on a public port.

Examples

Exposing health, info and metrics (tested on Spring Boot 4.1.1)

Java
# application.properties
management.endpoints.web.exposure.include=health,metrics,info
management.endpoint.health.show-details=always
management.info.env.enabled=true

info.app.name=Webnest Product API
info.app.version=1.4.0
Output
GET /actuator/health
-> {"components":{"db":{"details":{"database":"H2","validationQuery":"isValid()"},"status":"UP"},
    "diskSpace":{"details":{"total":183500795904,"free":130478673920,"threshold":10485760,...},"status":"UP"},
    "ping":{"status":"UP"}, ...},"status":"UP"}

GET /actuator/info
-> {"app":{"version":"1.4.0","name":"Webnest Product API"}}

GET /actuator/metrics/jvm.memory.used
-> {"baseUnit":"bytes","description":"The amount of used memory",
    "measurements":[{"statistic":"VALUE","value":1.5507056E8}],"name":"jvm.memory.used",...}

(With show-details=when-authorized and no Spring Security, /actuator/health
returns only {"status":"UP"}.)

A custom health indicator for an external payment service

Java
import org.springframework.boot.health.contributor.Health;
import org.springframework.boot.health.contributor.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class PaymentServiceHealthIndicator implements HealthIndicator {

    private final PaymentClient client;

    public PaymentServiceHealthIndicator(PaymentClient client) {
        this.client = client;
    }

    @Override
    public Health health() {
        long started = System.currentTimeMillis();
        boolean reachable = client.ping();
        long tookMs = System.currentTimeMillis() - started;
        if (!reachable) {
            return Health.down().withDetail("reason", "payment provider did not answer").build();
        }
        return Health.up().withDetail("responseTimeMs", tookMs).build();
    }
}
Output
GET /actuator/health/paymentService
-> {"details":{"responseTimeMs":0},"status":"UP"}

(after the provider stops answering)
GET /actuator/health
-> HTTP 503, {"components":{..., "paymentService":{"details":{"reason":"payment provider did not answer"},"status":"DOWN"}, ...},"status":"DOWN"}

Counting a business event with Micrometer

Java
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    private final Counter ordersPlaced;

    public OrderController(MeterRegistry registry) {
        this.ordersPlaced = Counter.builder("orders.placed")
                .description("Orders accepted by the API")
                .register(registry);
    }

    @PostMapping("/orders")
    public String placeOrder() {
        ordersPlaced.increment();
        return "order accepted";
    }
}
Output
POST /orders   (twice)
GET /actuator/metrics/orders.placed
-> {"availableTags":[],"description":"Orders accepted by the API",
    "measurements":[{"statistic":"COUNT","value":2.0}],"name":"orders.placed"}

Common Mistakes

  • Exposing all Actuator endpoints (management.endpoints.web.exposure.include=*) publicly in production, revealing environment variables, bean definitions, and internal request mappings to anyone.
  • Expecting /actuator/info to work after adding the starter. Only health is exposed by default, so info returns 404 until it is added to management.endpoints.web.exposure.include.
  • Setting show-details=when-authorized in an application without Spring Security and wondering why the component breakdown never appears.
  • Never securing Actuator endpoints with Spring Security, leaving operational internals unauthenticated.
  • Forgetting that /actuator/health checks configured components (database, disk) and can report DOWN even when the web server itself is running fine.
  • Doing slow work inside a custom HealthIndicator, such as a full API call with a long timeout. Probes call health often, so keep the check quick and give it a short timeout.

Exercise

Using the lesson's Exposing health, info and metrics (tested on Spring Boot 4.1.1) example, create a small implementation or design sketch that demonstrates spring-boot-starter-actuator adds production-ready monitoring endpoints with minimal setup.. Add a test case or scenario that would catch Exposing all Actuator endpoints (management.endpoints.web.exposure.include=*) publicly in production, revealing environment variables, bean definitions, and internal request mappings to anyone., and describe the expected result.

Show hints
  • Start with Adding Actuator and the /actuator/health Endpoint and compare your approach with Exposing health, info and metrics (tested on Spring Boot 4.1.1). Identify the decision or behavior the lesson recommends.
  • Walk through your scenario step by step. Confirm that it follows spring-boot-starter-actuator adds production-ready monitoring endpoints with minimal setup. and that it would catch the failure described by Exposing all Actuator endpoints (management.endpoints.web.exposure.include=*) publicly in production, revealing environment variables, bean definitions, and internal request mappings to anyone..

Quick quiz

1. Which choice is a mistake to avoid in Spring Boot Actuator?

  • A. spring-boot-starter-actuator adds production-ready monitoring endpoints with minimal setup.
  • B. Exposing all Actuator endpoints (management.endpoints.web.exposure.include=*) publicly in production, revealing environment variables, bean definitions, and internal request mappings to anyone.
  • C. Expecting /actuator/info to work after adding the starter. Only health is exposed by default, so info returns 404 until it is added to management.endpoints.web.exposure.include.
Show answer

B. Avoid this approach: Exposing all Actuator endpoints (management.endpoints.web.exposure.include=*) publicly in production, revealing environment variables, bean definitions, and internal request mappings to anyone. The lesson recommends: spring-boot-starter-actuator adds production-ready monitoring endpoints with minimal setup.

Interview questions

How would you apply the guidance in Adding Actuator and the /actuator/health Endpoint to a real task, and what failure would you guard against?

Show answer

spring-boot-starter-actuator adds production-ready monitoring endpoints with minimal setup. Apply this in Adding Actuator and the /actuator/health Endpoint; the example Exposing health, info and metrics (tested on Spring Boot 4.1.1) shows one way to do it. Avoid Exposing all Actuator endpoints (management.endpoints.web.exposure.include=*) publicly in production, revealing environment variables, bean definitions, and internal request mappings to anyone. and explain how your implementation or design prevents that failure.

Key Points to Remember

  • spring-boot-starter-actuator adds production-ready monitoring endpoints with minimal setup.
  • /actuator/health reports UP/DOWN status for the app and its key dependencies, commonly polled by load balancers.
  • /actuator/metrics exposes JVM, HTTP, and datasource metrics, and integrates with Micrometer for external monitoring tools.
  • Only health is exposed over HTTP by default; opt in to info, metrics and others explicitly and secure them.
  • A custom HealthIndicator adds your own dependencies to the health check, and a DOWN component makes the endpoint return HTTP 503.
  • Use MeterRegistry counters and timers to publish business metrics alongside the built-in ones.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering