Actuator Endpoints Interview Questions & Answers
Spring Boot Actuator endpoints for production-ready monitoring — /health, /info, /metrics, /loggers, /env, exposing vs enabling endpoints, health groups, securing endpoints, a separate management port, and custom @Endpoint beans.
Spring Boot Actuator adds production-ready features to your app — built-in HTTP (and JMX) endpoints that let you monitor and manage a running application: check health, view metrics, inspect configuration, change log levels, and more. It turns your service into something operable without writing any of that plumbing yourself.
<!-- pom.xml: one dependency unlocks all the endpoints -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
The value is observability out of the box: load balancers can poll /actuator/health, monitoring
tools can scrape /actuator/metrics, and on-call engineers can diagnose a live instance — all from
conventions Boot already wired up.
Rule of thumb: Add spring-boot-starter-actuator to every service you intend to run in production —
it's the standard way to make a Spring Boot app monitorable.
Add the spring-boot-starter-actuator dependency. Boot's auto-configuration then registers the
endpoints and their infrastructure — no extra code or annotations required.
// build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
Once it's on the classpath, the app exposes the actuator endpoints under the /actuator base path.
By default only /health is reachable over HTTP — everything else is registered but not web-exposed
until you opt in (a deliberately safe default).
Rule of thumb: Just add the starter — auto-configuration does the rest; you only touch properties when you want to change exposure, security, or the base path.
Actuator ships a rich set of built-in endpoints, each with a stable id under /actuator:
/health liveness/readiness + component health (DB, disk, etc.)
/info arbitrary app info (build, git, env)
/metrics Micrometer metrics (JVM, HTTP, datasource, custom)
/env Environment properties and property sources
/beans every Spring bean in the context
/mappings all @RequestMapping routes
/loggers view and CHANGE log levels at runtime
/threaddump a JVM thread dump
/heapdump downloads a heap dump (.hprof) file
/httpexchanges last N HTTP request/response exchanges
/shutdown gracefully shuts the app down (disabled by default)
/health and /metrics are the everyday operational endpoints; /env, /beans, and /mappings are
diagnostic; /threaddump and /heapdump are for troubleshooting hangs and leaks.
Rule of thumb: Know /health and /metrics cold — they're the two you'll wire into monitoring;
treat the rest as diagnostics you expose selectively.
These are two independent gates. Enabling decides whether the endpoint exists in the application at all; exposing decides whether an enabled endpoint is reachable over a transport (web or JMX). An endpoint must be both enabled and exposed to be callable over HTTP.
management:
endpoint:
shutdown:
enabled: true # ENABLE: the endpoint now exists (off by default)
endpoints:
web:
exposure:
include: health,info,shutdown # EXPOSE: make these reachable over HTTP
Most endpoints are enabled by default but not web-exposed (only /health is). /shutdown is the
exception — it's disabled by default and must be explicitly enabled before exposing.
Rule of thumb: Remember it as "enabled = it exists, exposed = you can reach it" — for most endpoints
you only adjust exposure; for /shutdown you must enable it too.
It's a secure-by-default choice: many endpoints (/env, /beans, /heapdump) leak sensitive
internals, so Boot only web-exposes the harmless /health until you explicitly opt in. You broaden
exposure with management.endpoints.web.exposure.include (and can subtract with exclude).
management:
endpoints:
web:
exposure:
include: health,info,metrics,loggers # whitelist what you want
# include: "*" # everything — convenient but dangerous unprotected
exclude: env,beans # exclude wins over include
Use a specific list in production rather than "*". If you do use the wildcard, secure the
endpoints (auth, separate port) — see the security questions.
Rule of thumb: Expose the minimum set you actually monitor; reach for include: "*" only behind
authentication or on a locked-down management port.
All web-exposed endpoints live under a common base path, /actuator by default — so health is
/actuator/health, metrics is /actuator/metrics, and so on. You can rename it with
management.endpoints.web.base-path, and remap individual endpoint paths if needed.
management:
endpoints:
web:
base-path: /manage # now /manage/health, /manage/metrics, ...
path-mapping:
health: healthcheck # /manage/healthcheck instead of /manage/health
Teams often change the base path to avoid clashing with application routes, to match an existing infrastructure convention, or as light obscurity behind a gateway.
Rule of thumb: Leave it as /actuator unless you have a real reason (route collision or a platform
convention) to rename it — tools expect the default.
/health aggregates health indicators (datasource, disk space, Redis, etc.) into a single overall
status — UP, DOWN, OUT_OF_SERVICE, or UNKNOWN. By default it shows only the top-level status;
show-details controls whether the per-component breakdown is included.
management:
endpoint:
health:
show-details: when-authorized # never (default) | when-authorized | always
show-components: when-authorized
- never — only
{"status":"UP"}, safe for anonymous load-balancer probes. - when-authorized — full detail only to authenticated users with the right role.
- always — full breakdown to everyone (handy in dev, risky in prod).
The overall status maps to an HTTP code (200 for UP, 503 for DOWN), which is exactly what an orchestrator's probe needs.
Rule of thumb: Keep show-details at never or when-authorized in production — the bare status is
all a public probe should see.
A health group bundles a subset of health indicators under its own endpoint, so you can expose different views for different consumers. The canonical use is Kubernetes liveness and readiness probes, which need to mean different things.
management:
endpoint:
health:
group:
liveness: # /actuator/health/liveness
include: livenessState
readiness: # /actuator/health/readiness
include: readinessState,db,redis
Liveness answers "is the process broken, restart me?"; readiness answers "can I take traffic right
now?". A failed dependency should fail readiness (stop routing traffic) but not liveness (don't
kill the pod). Boot auto-configures livenessState/readinessState indicators when it detects
Kubernetes.
Rule of thumb: Map readiness to your external dependencies and liveness to just the process — never let a transient DB blip trigger a pod restart.
Set management.server.port to run the actuator endpoints on a different port from your
application traffic. This lets you keep the management port internal (firewalled, not in the public
load balancer) while the app's main port serves users.
server:
port: 8080 # application traffic
management:
server:
port: 8081 # actuator endpoints only, e.g. /actuator/* on :8081
address: 127.0.0.1 # optionally bind to loopback / internal interface only
With a separate port you can let your network layer block :8081 from the outside world entirely, which
is a strong, simple way to keep sensitive endpoints off the public internet.
Rule of thumb: In production, put actuator on its own internal port (and optionally bind it to a private interface) so management traffic never shares the public listener.
Web-exposed actuator endpoints are not secured automatically — if Spring Security isn't on the
classpath, an exposed /env, /heapdump, or /shutdown is wide open. That's dangerous because
these leak secrets (env vars, datasource URLs), allow heap dumps full of in-memory data, or even shut the
app down. Lock them down with Spring Security.
@Bean
SecurityFilterChain actuator(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint()) // matches /actuator/**
.authorizeHttpRequests(reg -> reg
.requestMatchers(EndpointRequest.to("health")).permitAll() // health is public
.anyRequest().hasRole("ADMIN")) // the rest: ADMIN only
.httpBasic(withDefaults());
return http;
}
Defense in depth: expose the minimum set, require authentication/roles, and put management on a
separate internal port. Never expose include: "*" on a public, unauthenticated port.
Rule of thumb: Treat actuator like an admin console — authenticate everything except /health, and
never assume the framework secured it for you.
Endpoints can be exposed over two transports: HTTP (web) and JMX. They're configured independently, so an endpoint reachable over JMX isn't necessarily reachable over HTTP.
management:
endpoints:
web:
exposure:
include: health,info # what's reachable via HTTP
jmx:
exposure:
include: "*" # what's reachable via JMX (MBeans)
In modern Boot, JMX is disabled by default (spring.jmx.enabled=false) because most teams use HTTP +
Micrometer instead. JMX is still useful for local debugging with JConsole/VisualVM or legacy monitoring
that speaks MBeans.
Rule of thumb: Default to web exposure for cloud-native monitoring; only turn on JMX if a specific tool or legacy setup requires MBeans.
/info is filled by info contributors. The common ones surface build, git, env, java,
and os information — but several are off until you enable them and produce the metadata.
management:
info:
build.enabled: true # reads META-INF/build-info.properties
git.enabled: true # reads git.properties (mode: full for details)
java.enabled: true # JVM vendor/version
os.enabled: true # OS name/arch
env.enabled: true # any 'info.*' property below
info:
app:
name: Order Service # custom info.* keys appear verbatim
You generate build-info.properties with the Spring Boot Maven/Gradle plugin's build-info goal, and
git.properties with the git-commit-id plugin — then /info reports the exact version and commit
running.
Rule of thumb: Wire up the build and git plugins so /info reports the precise artifact version and
commit — invaluable for confirming what's actually deployed.
Several endpoints are information-disclosure or control hazards and must never be public:
/env leaks property values — datasource URLs, credentials, secrets
/heapdump downloads full JVM memory — passwords, tokens, PII in memory
/threaddump can reveal internal structure and in-flight data
/shutdown lets a caller stop the application (DoS) — disabled by default
/configprops shows resolved configuration, often with secrets
/loggers POST can change log levels — could flood logs or hide activity
Boot sanitizes known secret keys in /env and /configprops (showing ******), but that masking is
pattern-based and not foolproof. The safe posture is to not expose these at all, or only behind
authentication on an internal management port.
Rule of thumb: Keep /env, /heapdump, and /shutdown off public exposure entirely — they're the
endpoints attackers look for first.
The /loggers endpoint reports every logger's configured and effective level, and — via a POST
— lets you change a level at runtime without restarting. This is gold for debugging a live incident:
bump one package to DEBUG, capture the evidence, then set it back.
# Inspect a single logger
curl localhost:8080/actuator/loggers/com.example.orders
# Raise it to DEBUG live (no redeploy)
curl -X POST localhost:8080/actuator/loggers/com.example.orders \
-H 'Content-Type: application/json' \
-d '{"configuredLevel":"DEBUG"}'
# Reset to inherited level
curl -X POST localhost:8080/actuator/loggers/com.example.orders \
-H 'Content-Type: application/json' -d '{"configuredLevel":null}'
Because it mutates behavior, /loggers is a write endpoint — protect it like any admin action.
Rule of thumb: Use /loggers to turn on DEBUG for one package during an incident instead of
redeploying — but secure it, since it changes the running app.
Annotate a bean with @Endpoint (giving it an id) and mark methods with @ReadOperation,
@WriteOperation, or @DeleteOperation. Boot maps it to /actuator/<id> over web and JMX, with
the same exposure/security rules as built-ins.
@Component
@Endpoint(id = "features") // GET/POST /actuator/features
public class FeatureFlagsEndpoint {
private final Map<String, Boolean> flags = new ConcurrentHashMap<>();
@ReadOperation // HTTP GET
public Map<String, Boolean> all() { return flags; }
@WriteOperation // HTTP POST: /actuator/features {name,enabled}
public void set(String name, boolean enabled) { flags.put(name, enabled); }
}
Remember it still needs to be exposed (exposure.include) to be reachable. Use
@WebEndpoint/@JmxEndpoint to restrict it to a single transport.
Rule of thumb: Reach for a custom @Endpoint when you need operational control specific to your app
(feature flags, cache eviction) — and don't forget to expose and secure it like any other endpoint.
More Actuator & Observability interview questions
More ways to practice
The self-quiz is live. Join our channel for updates, new content & tech tips.