Spring Boot vs Micronaut — Which One I'd Pick for a Greenfield Service

by Arif Ikhsanudin, Backend Developer

The cold-start argument is real, but context-dependent

Your Lambda functions are timing out on cold starts. Or your Kubernetes cluster is slow to scale because new pod instances take 8-12 seconds to become healthy. Someone on the team mentions Micronaut or Quarkus. The pitch: sub-200ms startup times, lower memory footprint, GraalVM native image support. It is a real pitch. Here is whether it holds up for your situation.

What Micronaut does differently

Spring Boot's dependency injection is runtime-based. At startup, Spring scans the classpath, builds a bean graph, resolves proxies, and instantiates components. This is powerful and flexible — Spring can wire beans dynamically at runtime based on conditions — but it is also what makes Spring Boot applications take 6-15 seconds to start on typical workloads and consume 250-500MB of heap at idle.

Micronaut moves all of this to compile time. Its annotation processor generates the injection code during the build. At runtime, there is no reflection, no classpath scanning, no proxy generation. The result is startup times in the 100-500ms range and heap usage around 50-100MB idle for a comparable service.

// Micronaut — same annotation style as Spring, different engine underneath
@Singleton
public class PaymentService {

    private final PaymentGateway gateway;
    private final OrderRepository orders;

    // Injected at compile time — no runtime reflection
    public PaymentService(PaymentGateway gateway, OrderRepository orders) {
        this.gateway = gateway;
        this.orders = orders;
    }

    public PaymentResult process(UUID orderId, PaymentRequest request) {
        var order = orders.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
        return gateway.charge(order.getTotal(), request.getToken());
    }
}

The annotation surface is intentionally similar to Spring. Migrating familiarity is straightforward. Migrating actual Spring code is not — the dependency resolution model is different enough that you cannot drop-in replace Spring dependencies.

The ecosystem gap is the real cost

Spring Boot's ecosystem is 20 years deep. Spring Data JPA, Spring Security, Spring Batch, Spring Cloud, Spring AMQP — these are production-hardened libraries with extensive documentation, Stack Overflow coverage, and known failure modes. When something breaks at 2am, there is an answer somewhere.

Micronaut's ecosystem is functional but thinner. Micronaut Data is good, Micronaut Security covers the common cases, but you will hit edges earlier. Third-party library support varies — if a library assumes Spring's ApplicationContext or uses Spring's @Conditional mechanism, it will not work without adaptation. This is not a blocker but it is a real tax on integration work.

The GraalVM native image story is also more complex than the demos suggest. Native compilation of a Micronaut service works well for greenfield services that control their full dependency tree. The moment you pull in a library that uses reflection internally — and many do — you need to supply GraalVM reflection configuration manually or the native image will fail at runtime in non-obvious ways.

# What native compilation actually looks like
./mvnw package -Dpackaging=native-image

# Build time: 2-5 minutes on a modern laptop
# Result: single binary, ~50MB, starts in <100ms
# Caveat: any dynamic class loading breaks this

Deployment context determines the winner

Where Micronaut wins clearly:

  • AWS Lambda or Google Cloud Functions with consistent cold-start SLA requirements. A Micronaut native image that starts in 80ms versus a Spring Boot JAR that starts in 8 seconds is a meaningful user experience difference in serverless contexts.
  • High-density Kubernetes deployments where you are trying to run many small service instances per node and memory per pod is a cost line you are actively managing.
  • New teams choosing a framework without existing Spring investment — the learning curve difference is smaller than teams with Spring expertise assume.

Where Spring Boot wins:

  • Teams with existing Spring expertise. The productivity advantage of a known ecosystem outweighs Micronaut's technical advantages for most delivery timelines.
  • Services with complex integration requirements — messaging with Spring AMQP, batch processing with Spring Batch, security with Spring Security's full OAuth2/OIDC support. These are production-proven. The Micronaut equivalents work but require more configuration.
  • Long-running services on traditional VMs or containers where JVM warm-up time is paid once and amortized over days of uptime. The startup time difference becomes irrelevant.

What I would actually pick

For a new service on Kubernetes with rolling deployments and pod autoscaling: Spring Boot with Java 21 virtual threads. The startup time improvement from virtual threads (JEP 444) is not as dramatic as Micronaut, but Spring Boot 3.x on Java 21 starts in 3-4 seconds and handles thousands of concurrent connections efficiently. That is good enough for 95% of Kubernetes deployment patterns.

For serverless or any context where cold starts are a product requirement: Micronaut with native image if the team can afford the build complexity, or Spring Boot with GraalVM native support (Spring Boot 3.x has first-class native support via Spring Native) if the team is Spring-native.

Verify your cold-start budget before choosing. Most teams that choose Micronaut for cold-start performance have never actually measured their Spring Boot startup time with the JVM tuned for containerized environments. JAVA_TOOL_OPTIONS=-XX:TieredStopAtLevel=1 alone cuts Spring Boot startup from 8s to 3s on many services.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Setting Career Goals as a Contractor

No promotion cycle. No manager checking your progress. As a contractor, your career only moves if you decide where it’s going.

Read more

How to Design APIs That Survive Version Changes

APIs don’t break all at once. They slowly drift until something snaps. Good design isn’t about avoiding change — it’s about surviving it.

Read more

Multi-Stage Builds: The Dockerfile Trick That Shrinks Your Image

Multi-stage builds let you use a full build environment to compile your application and then copy only the result into a minimal runtime image — eliminating build tools, source code, and intermediate artifacts from what you actually ship.

Read more

Stop Paying Local Rates for Backend Work That Can Be Done Async and Remotely

Most backend work doesn't require someone in the same room, the same city, or even the same timezone. The pricing model should reflect that.

Read more