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,hashCodeand builders, our DTO code shrinks by roughly a third. Java records close much of that gap, but Kotlin adds default arguments, named parameters andcopy()on top. - Coroutines. Spring has supported Kotlin coroutines since Framework 5.2:
suspendcontroller methods,Flowreturn types and coroutine-awareWebClientgive 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-jsonauto-configures kotlinx.serialization next to Jackson 3. BeanRegistrarDsl. Programmatic bean registration withifandfor, which@Beanmethods cannot express.- Coroutine context propagation. Tracing and observability now work across
suspendfunctions. - Kotlin-first guides. Most popular Spring guides now have Kotlin versions.
Where Java is still stronger
- 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.
- 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.
- 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.
- Bytecode-sensitive frameworks. Kotlin classes are
finalby default, which breaks proxies in Spring AOP and Hibernate. Thekotlin-springandkotlin-jpacompiler 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,hashCodeandtoStringtouch lazy associations and break Hibernate's identity semantics. Use regular classes with an ID-basedequals, 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
- Add the Kotlin Gradle or Maven plugin with
kotlin-springandkotlin-jpa. Java and Kotlin can live in the same module. - Write new tests in Kotlin first. Low risk, and the team learns the language on real code.
- Write new classes in Kotlin; convert existing ones only when you are already changing them.
- 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.
Related guides
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
- Spring (2025). Spring Boot 4.0.0 available now.
- Spring (2025). Next level Kotlin support in Spring Boot 4.
- JetBrains (2025). Strengthening Kotlin for backend development: a strategic partnership with Spring.
- Spring Boot. Spring Boot 4.0 release notes and migration guide.
- Spring Framework docs. Kotlin support, coroutines and resilience features.
- Kotlin docs. Null safety, all-open and no-arg plugins, What's new in Kotlin 2.0.
- OpenJDK. JEP 444: Virtual Threads.
- Apache Kafka. Kafka 4.0 release announcement.
- Netflix. Hystrix status.
- JSpecify — standard nullness annotations for Java.