Scale and Monitor Micronaut in Production

Khimananda Oli 6 min read Programming and Languages
Scale and Monitor Micronaut in Production

By Khimananda Oli | Last reviewed: August 2026

Micronaut’s low-memory footprint and fast startup make it ideal for cloud-native Java, but default configurations rarely survive real traffic spikes or audit reviews. To reliably scale and monitor Micronaut in production, you must integrate Kubernetes Horizontal Pod Autoscaling (HPA) with custom Prometheus metrics and distributed tracing via OpenTelemetry. This combination ensures your services expand based on actual business load—not just CPU—while maintaining the observability required for SOC 2 compliance and rapid incident response.

Micronaut App/metrics + /healthPrometheusScrape & StoreK8s HPACustom Metrics APIGrafanaSLO DashboardsTempo / JaegerDistributed Traces
High-level architecture to scale and monitor Micronaut in production using integrated observability and autoscaling components

How Do You Configure Micronaut for Production Observability?

Before you can scale intelligently, your application must expose the right signals. Micronaut’s compile-time DI makes this lightweight, but you need explicit module dependencies. For any team aiming to understand Prometheus metrics fundamentals, Micronaut’s native integration is a strong starting point.

Enable Micrometer and OpenTelemetry

Add these dependencies to your build.gradle or pom.xml. In 2026, use Micronaut 4.x+ with Micrometer 1.13+ and OpenTelemetry SDK 1.40+ for full compatibility.

// build.gradle.kts
implementation("io.micronaut.micrometer:micronaut-micrometer-registry-prometheus")
implementation("io.micronaut.opentelemetry:micronaut-opentelemetry")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")

Configure Application Properties

In application.yml, expose metrics and enable tracing. Never run with default settings in production—always bind to specific paths and set sampling rates.

micronaut:
  metrics:
    enabled: true
    export:
      prometheus:
        enabled: true
        step: PT15S
  opentelemetry:
    enabled: true
    exporter:
      otlp:
        endpoint: https://otel-collector.internal:4317
        protocol: grpc
    sampler:
      ratio: 0.1 # Sample 10% of traces in prod

This configuration exposes /prometheus for scraping and sends traces via OTLP. The 10% sampling rate prevents trace volume from overwhelming your backend during peak load—a common mistake I see teams make when first adopting distributed tracing.

How Does Kubernetes HPA Work with Custom Micronaut Metrics?

CPU-based autoscaling fails for Java microservices because garbage collection and JIT compilation create misleading CPU spikes. Instead, scale on business-relevant metrics like HTTP requests per second or active connection count. This requires the Kubernetes HPA with custom metrics adapter.

Expose Custom Metrics via Micrometer

Micronaut automatically exports standard JVM and HTTP metrics. To add domain-specific counters, inject MeterRegistry:

@Singleton
public class OrderService {
    private final Counter orderCounter;

    public OrderService(MeterRegistry registry) {
        this.orderCounter = Counter.builder("orders.processed.total")
            .description("Total orders processed")
            .register(registry);
    }

    public void processOrder(Order order) {
        // business logic
        orderCounter.increment();
    }
}

Configure HPA with Custom Metrics

After installing the Prometheus Adapter in your cluster, define an HPA that targets your custom metric. This YAML assumes the adapter maps orders_processed_total to the Kubernetes custom metrics API.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: micronaut-order-service
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metric:
        name: orders_processed_per_second
      target:
        type: AverageValue
        averageValue: "50"

This scales pods when average throughput exceeds 50 orders/sec per replica. Always set minReplicas ≥ 2 for high availability—single-replica services violate basic resilience principles and fail most compliance audits.

Micronaut PodPrometheusProm AdapterK8s HPADeploymentscrape /metricsquery rate()custom metricscale replicas
Metric propagation path from Micronaut to Kubernetes HPA enabling intelligent autoscaling

What Are the Best Practices for Monitoring Micronaut Health and Performance?

Monitoring isn’t just dashboards—it’s defining what “healthy” means for your service. Align your monitoring strategy with the four golden signals: latency, traffic, errors, and saturation. Micronaut provides built-in health endpoints, but you must customize them for production.

Configure Liveness and Readiness Probes

Kubernetes uses these probes to restart unhealthy pods and remove unready ones from service load balancers. Misconfiguring them causes cascading failures during deployments.

endpoints:
  health:
    enabled: true
    sensitive: false
    details-visible: ANONYMOUS
liveness:
  enabled: true
  timeout: 3s
  interval: 10s
readiness:
  enabled: true
  timeout: 3s
  interval: 5s

Never use the same endpoint for both probes. Liveness should only check if the app can serve traffic (e.g., HTTP server running). Readiness should verify downstream dependencies (database, cache) are reachable. A pod that fails readiness but passes liveness stays alive but stops receiving new requests—this prevents error storms during partial outages.

Define SLIs and SLOs

Raw metrics are noise without context. Define Service Level Indicators (SLIs) and Objectives (SLOs) to distinguish signal from noise. For example:

  • Availability SLI: sum(rate(http_server_requests_seconds_count{status=~"2.."}[5m])) / sum(rate(http_server_requests_seconds_count[5m]))
  • SLO: 99.9% successful requests over 30 days
  • Latency SLI: p95 of http_server_requests_seconds_bucket < 200ms

Track error budgets weekly. If you burn through your budget early, freeze feature releases until reliability recovers. This discipline separates mature teams from those constantly firefighting.

How Do Micronaut Scaling Strategies Compare for Cloud-Native Deployments?

Not all scaling approaches fit every workload. Choose based on your traffic patterns, compliance needs, and operational maturity. Below is a practical comparison grounded in real 2026 production deployments.

StrategyBest ForKey LimitationCompliance Fit
HPA + Custom MetricsSteady-state APIs with measurable throughputRequires Prometheus Adapter setupHigh (audit-friendly metrics)
VPA (Vertical Pod Autoscaler)Memory-bound batch jobs or legacy libsCauses pod restarts; not for stateful appsMedium (restarts complicate logs)
KEDA (Event-Driven Scaling)Queue consumers, event processorsComplex CRDs; newer ecosystemHigh (scales to zero supported)
Cluster Autoscaler OnlyUnpredictable burst workloadsSlow node provisioning (2–5 min)Low (no app-level control)

For most Micronaut services handling REST/gRPC traffic, HPA with custom metrics remains the gold standard. Reserve KEDA for async workers consuming Kafka or SQS queues. Avoid VPA for web-facing services—the mandatory restarts break user sessions and inflate error rates during scaling events.

Operational Complexity →Scaling Responsiveness ↑HPAKEDAVPACA Only
Trade-off visualization for Micronaut scaling strategies balancing responsiveness against operational overhead

Scale and Monitor Micronaut in Production: Your Next Steps

Getting scale and monitor Micronaut in production right requires treating observability as a first-class feature, not an afterthought. Start by enabling Prometheus metrics and OpenTelemetry tracing in your next sprint. Then implement HPA with at least one custom metric tied to business value. Finally, define one SLO per critical service and build a Grafana dashboard around it. These steps form the foundation of a compliant, resilient platform that survives both traffic spikes and auditor scrutiny.

If your team needs help designing a production-grade Micronaut observability stack or preparing for SOC 2 evidence collection, reach out to discuss your architecture. I’ve guided multiple fintech and SaaS teams through this exact transition in Nepal and globally.

Frequently Asked Questions

Add the micronaut-micrometer-core dependency and configure your registry. For Prometheus, include micronaut-micrometer-registry-prometheus and expose the /metrics endpoint via management endpoints configuration in application.yml to allow scraping by monitoring systems.

Use Horizontal Pod Autoscaler targeting custom metrics or CPU. Configure readiness probes using /health/ready and liveness probes via /health/live. Ensure statelessness and externalize sessions to Redis or similar stores for consistent scaling behavior across pods.

Yes. Use GraalVM Native Image with the micronaut-aot module to reduce startup time to milliseconds. This enables rapid autoscaling response during traffic spikes while lowering memory footprint per instance compared to standard JVM deployments in 2026.

Integrate OpenTelemetry using micronaut-tracing-opentelemetry. Configure an OTLP exporter to send spans to Jaeger or Tempo. Automatic instrumentation covers HTTP clients, database calls, and messaging, providing end-to-end visibility without manual span creation in most cases.

Set -XX:+UseContainerSupport and -XX:MaxRAMPercentage=75.0 to respect container limits. Use G1GC or ZGC for low-latency workloads. Avoid fixed heap sizes; let the JVM adapt to cgroup memory constraints to prevent OOM kills during scaling events.

Never expose management ports publicly. Bind them to localhost or a separate internal port. Apply authentication via micronaut-security or network policies. Restrict access to /metrics, /health, and /env endpoints using role-based rules or mTLS between services.

Yes. Use micronaut-kafka or micronaut-rabbitmq with reactive consumers. Tune concurrency via consumer groups and prefetch settings. Backpressure is handled natively through Project Reactor, preventing overload during bursty message ingestion while maintaining low latency processing.

Output structured JSON logs using logback-json-classic. Include trace IDs via MDC for correlation. Ship logs directly to Fluent Bit or Vector sidecars to avoid blocking application threads. Never write to local disk in ephemeral container environments.

Micronaut uses compile-time DI instead of reflection, resulting in lower memory usage and faster startup. This makes it more cost-efficient for serverless and elastic scaling scenarios where cold starts and resource density directly impact infrastructure spend.

Health checks may timeout if dependent services are saturated. Configure separate timeouts for readiness probes and add circuit breakers around external dependencies. Use cached health responses with short TTLs to prevent cascading failures during transient downstream issues.

Expose executor metrics via Micrometer. Track active, queued, and completed tasks for each named executor. Set alerts when queue depth exceeds thresholds or rejection counts increase, indicating insufficient thread capacity or blocking operations in reactive pipelines.

Lower memory and CPU usage per request reduces instance count. Faster startup allows smaller auto-scaling buffers. Teams typically see twenty to forty percent savings on compute costs due to efficient resource utilization and reduced cold-start penalties.

Implement graceful shutdown with micronaut-management to finish in-flight requests. Use rolling updates with maxSurge and maxUnavailable set appropriately. Combine with service mesh retries and circuit breaking to mask brief unavailability during pod termination cycles.

gRPC connections are long-lived, causing uneven load distribution. Enable client-side load balancing or use a service mesh like Envoy. Configure keepalive settings and connection pooling to prevent stale connections from skewing traffic during scaling events.

Run micronaut-cli validate-config during CI to catch misconfigurations early. Use environment-specific property sources and fail-fast validation beans. Test against actual secret managers and config servers in staging to ensure runtime resolution matches expected production behavior.