Over the past three years, 70% of our new JVM projects started in Kotlin. No hype and no religion in this post — just the engineering arguments for where Kotlin beats Java on Spring Boot, where we still write plain Java, and what Spring Boot 4 changed in that equation. At the end you'll find the exact microservices stack we start new projects with in 2026 and a migration path for existing Spring Boot 3 services.

Spring Boot 3.5 or 4.0 in 2026?

Spring Boot 4.0 was released on November 20, 2025, on top of Spring Framework 7 (Spring blog, 2025). It keeps Java 17 as the minimum, adds first-class Java 25 support, splits the codebase into smaller modules and brings API versioning and HTTP service clients for REST applications.

Open-source support for Spring Boot 3.5, the last 3.x line, ends on June 30, 2026; after that, fixes come only through commercial support (Spring Boot support timeline). Our rule of thumb:

  • New services: start on Spring Boot 4 with Kotlin.
  • Existing 3.x services: upgrade to 3.5 first, fix deprecations, then move to 4.x following the official migration guide.

Why we pick Kotlin by default

  • Null safety at the language level. Nullable and non-nullable types are different types, so an entire class of NullPointerExceptions is caught by the compiler (Kotlin docs: null safety).
  • Concise data classes. Compared with classic Java DTOs with getters, equals, hashCode and builders, our DTO code shrinks by roughly a third. Java records close much of that gap, but Kotlin adds default arguments, named parameters and copy() on top.
  • Coroutines. Spring has supported Kotlin coroutines since Framework 5.2: suspend controller methods, Flow return types and coroutine-aware WebClient give you non-blocking code that reads like blocking code, without Reactor operators (Spring docs: coroutines).
  • Extension functions. Cleaner domain code without StringUtils-style static helpers.
  • 100% Java interoperability. Every Java library, from Hibernate to the Kafka client, works unchanged (Kotlin docs: calling Java from Kotlin).

Here is what a typical endpoint looks like:

data class OrderDto(
    val id: UUID,
    val customerId: UUID,
    val total: BigDecimal,
    val note: String? = null,          // nullable by design, enforced by the compiler
)

@RestController
@RequestMapping("/orders")
class OrderController(private val orders: OrderService) {

    @GetMapping("/{id}")
    suspend fun get(@PathVariable id: UUID): OrderDto =
        orders.find(id) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)

    @GetMapping
    fun stream(): Flow<OrderDto> = orders.streamRecent()
}

What Spring Boot 4 changed for Kotlin

In May 2025 JetBrains and the Spring team announced a strategic partnership to make Kotlin a first-class choice for Spring backends (JetBrains blog, 2025). Spring Boot 4 is the first release shaped by it (Next level Kotlin support in Spring Boot 4):

  • Kotlin 2.2 baseline. Spring Boot 4 and Framework 7 require Kotlin 2.2 or later.
  • JSpecify null-safety across the portfolio. Spring, Reactor and Micrometer APIs are annotated with JSpecify, so Kotlin sees proper nullable and non-nullable types instead of unsafe platform types. This was the biggest remaining hole in Kotlin's null safety on Spring.
  • Kotlin Serialization starter. spring-boot-starter-kotlinx-serialization-json auto-configures kotlinx.serialization next to Jackson 3.
  • BeanRegistrarDsl. Programmatic bean registration with if and for, which @Bean methods cannot express.
  • Coroutine context propagation. Tracing and observability now work across suspend functions.
  • Kotlin-first guides. Most popular Spring guides now have Kotlin versions.

Where Java is still stronger

  1. High-load, low-latency services. JVM tuning knowledge, GC write-ups and performance tooling are overwhelmingly Java-centric. Kotlin compiles to the same bytecode, but your team will debug with Java examples.
  2. Teams where every senior has written Java for 5+ years. Retraining costs more than the gain, especially since modern Java (records, pattern matching, virtual threads) has closed much of the ergonomic gap.
  3. Static analysis. Error Prone, NullAway and SpotBugs are Java-first. For Kotlin we use detekt and ktlint, which are good but have a smaller rule ecosystem.
  4. Bytecode-sensitive frameworks. Kotlin classes are final by default, which breaks proxies in Spring AOP and Hibernate. The kotlin-spring and kotlin-jpa compiler plugins fix it, but you must know to add them (all-open plugin, no-arg plugin).

Coroutines or virtual threads?

Java 21 virtual threads, enabled in Spring Boot with spring.threads.virtual.enabled=true, give plain blocking code most of the scalability benefits that used to require reactive stacks (JEP 444). Our split:

  • Virtual threads for classic request-response services on Spring MVC with JDBC. Zero code changes, and they work with Java and Kotlin alike.
  • Coroutines when you need structured concurrency in business logic: fan-out calls to several services, timeouts and cancellation that propagate correctly.

Pitfalls we hit on real projects

  • Don't use data classes for JPA entities. Generated equals, hashCode and toString touch lazy associations and break Hibernate's identity semantics. Use regular classes with an ID-based equals, or Spring Data JDBC, which suits immutable Kotlin classes better.
  • Configure Jackson for Kotlin. Without the Kotlin module, default values and nullability are ignored during deserialization. Spring Boot registers it automatically when it is on the classpath; make sure it is.
  • Watch build times. The K2 compiler in Kotlin 2.0+ roughly doubled compilation speed in JetBrains' benchmarks (What's new in Kotlin 2.0), but annotation processing via kapt is still slow. Prefer KSP where libraries support it.

Our typical stack in 2026

Layer Choice Why
Framework Spring Boot 4.x + Kotlin 2.2+ JSpecify null-safety, coroutines, modular starters
Runtime Java 21 or 25 LTS Virtual threads, modern GC
API gateway Spring Cloud Gateway Same programming model as the services
Discovery Kubernetes Services, Consul outside Kubernetes Eureka only for legacy
Database PostgreSQL + Hibernate 7 or Spring Data JDBC Hibernate 7.x ships with Spring Boot 4
Messaging Apache Kafka 4.x (KRaft) with Spring for Apache Kafka ZooKeeper-free since Kafka 4.0
Resilience Resilience4j, Spring Framework 7 @Retryable Netflix Hystrix is in maintenance mode
Observability OpenTelemetry via spring-boot-starter-opentelemetry One standard for traces, metrics and logs
Tests JUnit, Testcontainers 2, MockK Real dependencies in integration tests

A few notes on those choices. Kafka 4.0 removed ZooKeeper entirely and runs only in KRaft mode (Apache Kafka 4.0 release). Netflix put Hystrix into maintenance mode back in 2018 and recommends Resilience4j (Hystrix README); for simple retries and concurrency throttling, Spring Framework 7 now has built-in @Retryable and @ConcurrencyLimit (Spring docs: resilience features). Spring Boot 4 upgrades to Hibernate 7.x, Kafka 4.1, Jackson 3 and Testcontainers 2, and adds a dedicated OpenTelemetry starter (Spring Boot 4.0 release notes). Testcontainers remains the single most valuable testing tool in the stack.

Kotlin doesn't make you an architect. Bad code stays bad — just syntactically prettier. Don't confuse the tool with discipline.

Performance

In our benchmarks Spring Boot on Kotlin barely differs from Java: the gap stays within 1–3% throughput and 2–5 MB of memory. Both compile to JVM bytecode and run on the same JIT. The differences you'll see come from your code — boxing in generic collections, lambdas in hot loops — not from the language.

If you need fast startup and a small memory footprint, for example for scale-to-zero workloads, use GraalVM Native Image. Spring Boot supports it for both Java and Kotlin through Spring AOT (Spring Boot docs: GraalVM native images). Expect startup in tens of milliseconds, in exchange for longer builds and some reflection configuration.

How to introduce Kotlin into an existing Java service

  1. Add the Kotlin Gradle or Maven plugin with kotlin-spring and kotlin-jpa. Java and Kotlin can live in the same module.
  2. Write new tests in Kotlin first. Low risk, and the team learns the language on real code.
  3. Write new classes in Kotlin; convert existing ones only when you are already changing them.
  4. Agree on conventions early: detekt and ktlint rules, when to use coroutines, how to handle nullability at Java boundaries.

On a typical 30–50k-line service, the team is productive in Kotlin within two to three sprints.

For the platform underneath, see Java 25 LTS: what's new and Virtual threads in Spring Boot. For structuring larger services without jumping to microservices, read Modular monolith with Spring Modulith, and for fast startup, GraalVM native image for Spring Boot.

To add LLM features to a Spring Boot service without leaving the JVM, see the Spring AI guide.

FAQ

Is Kotlin production-ready for Spring Boot? Yes. Spring has supported Kotlin officially since Framework 5.0, and Spring Boot 4 made it a first-class language with portfolio-wide null-safety (Spring docs: Kotlin).

Should we migrate from Spring Boot 3 to 4 now? For new services, start on 4. For existing ones, plan the move now: open-source support for 3.5 ends in June 2026, and only the 4.x line keeps receiving free fixes.

Is Kotlin slower than Java? Not measurably in typical services; both run the same bytecode on the same JVM.

Coroutines or WebFlux? For Kotlin teams, coroutines on top of WebFlux or Spring MVC with virtual threads. We no longer start new projects with raw Reactor operators.

Sources

  1. Spring (2025). Spring Boot 4.0.0 available now.
  2. Spring (2025). Next level Kotlin support in Spring Boot 4.
  3. JetBrains (2025). Strengthening Kotlin for backend development: a strategic partnership with Spring.
  4. Spring Boot. Spring Boot 4.0 release notes and migration guide.
  5. Spring Framework docs. Kotlin support, coroutines and resilience features.
  6. Kotlin docs. Null safety, all-open and no-arg plugins, What's new in Kotlin 2.0.
  7. OpenJDK. JEP 444: Virtual Threads.
  8. Apache Kafka. Kafka 4.0 release announcement.
  9. Netflix. Hystrix status.
  10. JSpecify — standard nullness annotations for Java.