Spring Boot Actuator
Spring Boot Actuator turns your application into a manageable, observable service by exposing a set of built-in HTTP (and JMX) endpoints for health, metrics, configuration, and runtime introspection. It is the foundation for operating Spring Boot in production: load balancers poll its health endpoint, monitoring systems scrape its metrics, and operators inspect beans, mappings, and log levels without redeploying.
Add a single starter and the endpoints appear automatically — you decide which ones to expose and how to secure them.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
In This Section
- Health Checks —
/actuator/health, liveness/readiness groups, custom indicators. - Metrics & Micrometer — meters, custom metrics, Prometheus export.
- Caching — the cache abstraction with
@Cacheable. - Redis Caching — Redis as a distributed cache provider.
- Scheduling Tasks —
@Scheduledjobs and cron. - Async Methods —
@AsyncandCompletableFuture. - Dockerizing Spring Boot — multi-stage builds and buildpacks.
- Graceful Shutdown — draining in-flight requests on SIGTERM.
- Performance Tuning — heap, pools, lazy init, virtual threads.
The endpoints
Each endpoint exposes a slice of runtime state under the /actuator base path. The most commonly used ones:
| Endpoint | Path | Purpose |
|---|---|---|
health | /actuator/health | Application and dependency health status |
info | /actuator/info | Arbitrary application info (build, git, custom) |
metrics | /actuator/metrics | Micrometer meters (memory, CPU, HTTP, JDBC) |
env | /actuator/env | Resolved Environment properties |
loggers | /actuator/loggers | View and change log levels at runtime |
mappings | /actuator/mappings | All @RequestMapping routes |
beans | /actuator/beans | Every bean in the application context |
configprops | /actuator/configprops | @ConfigurationProperties beans |
threaddump | /actuator/threaddump | JVM thread dump |
shutdown | /actuator/shutdown | Graceful shutdown (disabled by default) |
By default only health is exposed over HTTP. Everything else must be explicitly opted in.
Exposing endpoints
Control which endpoints are reachable over the web with management.endpoints.web.exposure.
management:
endpoints:
web:
exposure:
include: health, info, metrics, loggers, mappings
# exclude: env # remove a single endpoint from a wildcard include
base-path: /actuator # default; change to /manage if you like
endpoint:
health:
show-details: when-authorized
shutdown:
access: read-only # 'unrestricted' enables POST shutdown
Warning:
include: "*"exposes every endpoint, includingenv,heapdump, andthreaddump, which leak secrets and internals. Never use a wildcard on a public-facing port.
Inspecting the running app
With the endpoints exposed, a simple GET returns JSON.
curl http://localhost:8080/actuator/health
Output:
{
"status": "UP",
"components": {
"db": { "status": "UP", "details": { "database": "PostgreSQL", "validationQuery": "isValid()" } },
"diskSpace": { "status": "UP", "details": { "total": 250790436864, "free": 91234508800, "threshold": 10485760 } },
"ping": { "status": "UP" }
}
}
The info endpoint is empty until you populate it. Build and git metadata are added automatically when the relevant plugins run, plus any custom info.* properties.
info:
app:
name: Order Service
version: 2.4.1
management:
info:
git:
mode: full
env:
enabled: true
Output of /actuator/info:
{
"app": { "name": "Order Service", "version": "2.4.1" },
"git": { "branch": "main", "commit": { "id": "a1b2c3d", "time": "2026-06-13T09:12:04Z" } }
}
Changing log levels at runtime
The loggers endpoint can read and change a logger’s level without a restart — invaluable for debugging production incidents.
# Inspect the current level
curl http://localhost:8080/actuator/loggers/com.example.orders
# Raise it to DEBUG on the fly
curl -X POST http://localhost:8080/actuator/loggers/com.example.orders \
-H 'Content-Type: application/json' \
-d '{"configuredLevel":"DEBUG"}'
Securing Actuator
Actuator endpoints are HTTP routes, so they are secured like any other route with Spring Security. The cleanest production setup runs management on a separate port and locks the endpoints behind a role.
management:
server:
port: 9001 # isolate management traffic from the app port
endpoints:
web:
exposure:
include: health, info, metrics, prometheus
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class ActuatorSecurityConfig {
@Bean
SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
http
.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.anyRequest().hasRole("ACTUATOR"))
.httpBasic(org.springframework.security.config.Customizer.withDefaults());
return http.build();
}
}
Tip:
EndpointRequest.toAnyEndpoint()matches the configured base path automatically, so the filter chain keeps working even if you changebase-pathor the management port.
Note: Keep
/healthand/infopublic so probes and dashboards work without credentials, but require a role for everything that reveals internals (env,beans,loggers,threaddump).
Best Practices
- Expose only the endpoints you actually use; never wildcard on a public port.
- Run management on a separate
management.server.portand firewall it to your monitoring network. - Set
health.show-details: when-authorizedso anonymous probes see onlyUP/DOWN. - Secure non-trivial endpoints with a
SecurityFilterChainscoped viaEndpointRequest. - Add
gitandbuildinfo so deployed versions are traceable from/actuator/info.