Spring Boot Actuator Tutorial

Watch on YouTube

Spring Boot Actuator and Monitoring

In simple terms: Actuator gives you a window into a running Spring Boot application. It helps answer questions such as: “Is the application alive?”, “Is the database connected?”, “How many requests are failing?”, and “Is memory usage increasing?”
How monitoring works
ApplicationRuns business APIs
ActuatorCollects health and metrics
Monitoring toolPrometheus, Grafana, or cloud platform
TeamReceives alerts and investigates

What are Actuator and monitoring?

Monitoring means observing an application's health, performance, and behavior. Spring Boot Actuator provides ready-made endpoints for this purpose. These endpoints are different from business endpoints such as /api/orders; they are operational endpoints for developers, DevOps engineers, and platform systems.

For example, Kubernetes can call a health endpoint before sending users to a new application instance. Prometheus can read metrics, and Grafana can display them on a dashboard.

1. Add the Actuator dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Adding the starter creates Actuator endpoints, but most endpoints are not exposed over HTTP automatically. You must explicitly choose what should be available.

2. Health and readiness

Health answers whether an application can work correctly. A healthy response is useful for load balancers, containers, and operations teams.

GET /actuator/health

{
  "status": "UP",
  "components": {
    "db": { "status": "UP" },
    "diskSpace": { "status": "UP" }
  }
}

Liveness vs readiness

  • Liveness: The process is running. Restart it only when liveness fails.
  • Readiness: The application is ready to receive traffic. Do not send traffic when readiness fails.
management.endpoint.health.probes.enabled=true
management.health.livenessstate.enabled=true
management.health.readinessstate.enabled=true

# Common Kubernetes URLs
GET /actuator/health/liveness
GET /actuator/health/readiness

A database outage may make readiness fail while the Java process is still alive. The platform can temporarily remove that instance from traffic instead of restarting it unnecessarily.

3. Application information

The info endpoint displays safe build and application information. Do not put passwords, tokens, or private infrastructure details here.

management.info.env.enabled=true
info.app.name=employee-service
info.app.version=1.4.0
info.app.environment=production

GET /actuator/info

4. Metrics

Metrics are numeric measurements collected over time. They help you see trends rather than investigating only after a failure.

GET /actuator/metrics
GET /actuator/metrics/jvm.memory.used
GET /actuator/metrics/http.server.requests
GET /actuator/metrics/system.cpu.usage
Metric What it tells you Real use
http.server.requests Request count, status, and timing Find slow or failing endpoints
jvm.memory.used Memory used by the JVM Detect memory growth
jdbc.connections.active Database connections in use Find connection-pool pressure
hikaricp.connections.pending Requests waiting for a connection Detect database bottlenecks
process.cpu.usage CPU used by the process Decide when to scale

5. Expose only required endpoints

Configure endpoint exposure in application.properties. The include list adds endpoints; the exclude list removes endpoints even when a broad include is used.

# Beginner/local setup
management.endpoints.web.exposure.include=health,info,metrics

# Production: expose a small, deliberate set
management.endpoints.web.exposure.include=health,info,prometheus
management.endpoints.web.exposure.exclude=env,beans,configprops,threaddump

# Change the URL prefix if required
management.endpoints.web.base-path=/manage

With the custom base path, health is available at /manage/health. Never assume an endpoint is private just because its URL is difficult to guess.

6. Custom health indicators

Built-in health checks cover common dependencies. Add a custom indicator when your service depends on a payment gateway, warehouse API, message broker, or another business-critical system.

@Component("paymentGateway")
public class PaymentGatewayHealthIndicator
        implements HealthIndicator {

    private final PaymentGatewayClient client;

    public PaymentGatewayHealthIndicator(PaymentGatewayClient client) {
        this.client = client;
    }

    @Override
    public Health health() {
        try {
            client.ping();
            return Health.up()
                    .withDetail("provider", "ExamplePay")
                    .build();
        } catch (Exception ex) {
            return Health.down()
                    .withDetail("reason", "Payment gateway unavailable")
                    .build();
        }
    }
}

Use short timeouts in health checks. A health request should not hang because an external service is slow.

7. Add custom application information

@Component
public class DeploymentInfoContributor
        implements InfoContributor {

    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("region", "ap-south-1")
                .withDetail("service", "employee-service")
                .withDetail("release", "2026.07.24");
    }
}

8. Prometheus and Grafana

Prometheus periodically scrapes a metrics endpoint and stores the measurements. Grafana reads those measurements and displays charts and dashboards. Add Micrometer's Prometheus registry to publish metrics in Prometheus format.

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

management.endpoints.web.exposure.include=health,info,prometheus

GET /actuator/prometheus

Example Prometheus configuration:

scrape_configs:
  - job_name: employee-service
    metrics_path: /actuator/prometheus
    static_configs:
      - targets: ["employee-service:8080"]

9. View and change log levels

Actuator can show configured loggers and, when explicitly exposed, can temporarily change a logger level while diagnosing an issue.

management.endpoints.web.exposure.include=health,info,loggers,metrics

GET /actuator/loggers
GET /actuator/loggers/com.javacodeex.employee

POST /actuator/loggers/com.javacodeex.employee
Content-Type: application/json

{ "configuredLevel": "DEBUG" }

Protect this endpoint and return the level to its normal value after the investigation. Avoid enabling verbose logging for sensitive data.

10. Secure Actuator endpoints

Health may be public for a load balancer, but metrics, environment, and logging endpoints should normally require authentication and network restrictions.

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http)
        throws Exception {
    http.authorizeHttpRequests(auth -> auth
        .requestMatchers("/actuator/health/**").permitAll()
        .requestMatchers("/actuator/**").hasRole("OPS")
        .anyRequest().authenticated());
    return http.build();
}
management.endpoint.health.show-details=when_authorized

Do not expose env, configprops, or heapdump publicly. They may reveal configuration, memory contents, or infrastructure details.

11. Create a custom Actuator endpoint

A custom endpoint is useful for safe operational information that is not part of the default Actuator set. Keep it read-only unless there is a strong operational reason to support write operations.

@Component
@Endpoint(id = "deployment")
public class DeploymentEndpoint {

    @ReadOperation
    public Map<String, String> deployment() {
        return Map.of(
                "version", "2026.07.24",
                "region", "ap-south-1",
                "commit", "abc123");
    }
}
management.endpoints.web.exposure.include=health,info,deployment

GET /actuator/deployment

12. Real-world incident example

Suppose users report that checkout is slow. A simple investigation can follow this path:

  1. Check /actuator/health/readiness to confirm the instance can receive traffic.
  2. Check http.server.requests for checkout latency and 5xx responses.
  3. Check database connection metrics for active or pending connections.
  4. Check JVM memory and CPU to see whether the instance is overloaded.
  5. Use a protected logger endpoint temporarily if more application detail is needed.
  6. Fix the root cause, restore normal logging, and record the incident.

13. Container and Kubernetes usage

Containers use health probes to decide whether to restart an application or send traffic to it. Keep liveness checks lightweight and use readiness checks for dependencies that must be available before serving requests.

livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080

Best practices

  • Expose only the endpoints your platform actually needs.
  • Protect operational endpoints with authentication and network rules.
  • Keep health checks fast and use timeouts for external dependencies.
  • Use readiness for traffic decisions and liveness for restart decisions.
  • Monitor latency, error rate, traffic, and resource saturation together.
  • Never place secrets in the info endpoint or logs.
  • Use Prometheus and Grafana or an equivalent monitoring platform in production.
Security rule: Monitoring data is operational data. It can reveal database names, class names, memory contents, and deployment details, so treat Actuator endpoints as sensitive.

Spring Boot Actuator FAQs

What is the difference between liveness and readiness?

Liveness indicates whether the process should be restarted. Readiness indicates whether the instance is prepared to receive traffic.

Should all Actuator endpoints be public?

No. Expose only required endpoints and protect them because they can reveal deployment, configuration, memory, or dependency details.

How are Actuator metrics exported to Prometheus?

Add the Micrometer Prometheus registry, expose the Prometheus endpoint, and configure Prometheus to scrape it over a protected network.

Next: Deployment

Continue learning