With that upgrade, Kotlin 2.2 is the new baseline for Spring Framework 7.0.
With the upgrade, we should be able to leverage https://youtrack.jetbrains.com/issue/KT-75169 to remove @Suppress("EXTENSION_SHADOWED_BY_MEMBER") annotations.
Comment From: sdeleuze
I still see warnings in IntelliJ IDEA about @Suppress("EXTENSION_SHADOWED_BY_MEMBER") so I will update that later after JetBrains feedback.
Comment From: sdeleuze
No warnings in both Kotlin 2.2.0 compiler and IDEA 2024.2 EAP when removing @Suppress("EXTENSION_SHADOWED_BY_MEMBER") so I removed them.
Comment From: vlsi
@sdeleuze , could you please clarify why do you bump Kotlin API and language version? (see https://github.com/spring-projects/spring-framework/commit/ba9bef6bbfa8364e6b4fd95c383d10a2624a04c9 )
Technically speaking, if you target the newest Kotlin version, it forces everybody to upgrade to the latest Kotlin runtime which is not always easy to do.
Let me put an example from Java: * Currently Spring Framework targets Java 17, so it allows clients to use Java 17 runtime which has been released in 2021 (4 years ago). So if the client still uses Java 17 or Java 21, they are fine to use Spring Framework without dealing with their Java version. * However, for Kotlin you make the case a completely different. You target Kotlin 2.2 which as been released just a few months back. It effectively forces everybody to upgrade their Kotlin runtime to 2.2
Why don't you follow the same path for Kotlin which you do for Java? Why don't you "use the latest compiler, but target an older runtime"?
Frankly, the current setup of "target the latest Kotlin API and library versions" causes "kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 2.2.0, expected version is 1.9.0" errors.
It does not seem fair you allow 4 years slack for upgrading Java runtime while you leave just a few months for upgrading Kotlin runtime.
See: * https://github.com/Kotlin/api-guidelines/issues/44 * https://github.com/adobe/S3Mock/issues/2842 * https://github.com/GradleUp/Tapmoc
Comment From: sdeleuze
Multiple reasons: - Spring new major seems like the best opportunity to upgrade the baseline (we got a lot of ask to switch to Kotlin 2) - Some Kotlin libraries like Kotlin Serialization are not compatible with Kotlin 1.x and 2.x (due to the compiler plugin infra) for a given version, so we need to choose - Kotlin compiler supports only 2 minor previous releases (Spring Framework 7.1 is expected to leverage Kotlin 2.3 but still keep a Kotlin 2.2 baseline) - We want everybody being on K2 compiler since it fixes a lot of bugs for us where we had to workaround (one being linked in the description of this issue) and our users, we don't want to increase the maintenance cost by being too conservative - Kotlin only interprets out-of-the-box JSpecify annotation as Kotlin nullability as of Kotlin 2.1 so 2.1 was a minimum - Kotlin and Java baselines are different by nature, as Java baseline also controls the JDK runtime baseline (used by both Java and Kotlin languages) - Kotlin 2.2 refines some aspects of the JSpecify support
Comment From: vlsi
One thing I want to clarify (and I might be misunderstanding your “baseline” wording): most of the items listed sound like “we want/need a newer compiler toolchain (K2, bugfixes, better JSpecify inference, plugin alignment)”, not “we need to raise the Kotlin API/library baseline”.
Concretely, my understanding is that the following are still achievable while compiling Spring with a recent Kotlin compiler (e.g. 2.2.x / K2) but keeping -api-version 2.0 (and, if desired, -language-version 2.0).
- being on K2 to avoid compiler bugs / remove workarounds (toolchain choice)
- getting JSpecify → Kotlin nullability behavior (compiler behavior)
- getting 2.2 refinements in JSpecify support (compiler behavior)
- dealing with compiler plugin alignment (e.g. serialization) as a build/tooling constraint
- “major release is a good time to move” / “avoid extra maintenance” (policy/maintenance)
If the real constraint is something else — e.g. artifact/metadata compatibility for consumers on Kotlin 2.0 (i.e. older compilers failing to consume classes built with newer compilers regardless of apiVersion) — it would be great to call that out explicitly, because that is the only part that would actually force raising the Kotlin baseline from 2.0 to 2.2 (as opposed to “just” building Spring with a newer compiler).
Would you agree that the above reasons don’t inherently require Kotlin API/stdlib 2.2, and that the decision is primarily about consumer compiler compatibility / support policy rather than Spring needing 2.2-only APIs?
Comment From: sdeleuze
It is not just about the compiler version used by the Spring portfolio to build its dependencies, but also the version used by the Spring Boot application developers, as we don't want people using for example Kotlin 2.0 as that produces Spring API totally incompatible. We don't want to handle the related maintenance pain, we don't want our users to be exposed to Spring APIs using platform types because they use an older version of the Kotlin compiler.
To answer to your question about API version baseline, could you please share more about your use case causing "kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 2.2.0, expected version is 1.9.0" errors?
Comment From: vlsi
Spring APIs using platform types because they use an older version of the Kotlin compiler
Sébastien, I never suggested using outdated Kotlin compiler.
On contrary, I suggested using the latest Kotlin compiler.
What I suggest is to target older Kotlin release with apiVersion, languageVersion and coreLibrariesVersion settings.
Spring would still use the latest and greatest Kotlin compiler, while the binaries could be consumed by a wider range of Kotlin clients.
but also the version used by the Spring Boot application developers
I have no issues if Spring Boot application developers use Kotlin version they like. It should be the same as with Java versions, isn't it?
Some Spring Boot developers prefer using Java 17 even though it is not the very latest version.
don't want to handle the related maintenance pain
Can you quantify the exact maintenance pain?
we don't want our users to be exposed to Spring APIs using platform types because they use an older version of the Kotlin compiler
Correct me if I am wrong, but apiVersion=2.0, languageVersion=2.0, coreLibrariesVersion=2.0 does not result in platform types in Spring APIs. It would just ensure the resulting binaries are consumable with Kotlin 2.0, however, you could still use 2.2 compiler to get the latest bugfixes and so on.
could you please share more about your use case causing "kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 2.2.0, expected version is 1.9.0" errors?
The case is not directly related to Spring, but I have ran into it multiple times with various libraries that skip setting apiVersion, languageVersion, coreLibrariesVersion when building their Kotlin libraries.
- https://github.com/adobe/S3Mock/issues/2842.
I use Gradle 8.12 (because, why not?) for building Gradle plugin https://github.com/burrunan/gradle-s3-build-cache, and I used
kotlin-dslGradle's embedded Kotlin to build the plugin. That was the easiest ting to configure. Unfortunately, after bumping s3mock dependency I ran into "binary version metadata is 2.2.0 expected version is 2.0.0". The failure is caused by the fact that s3mock targets Kotlin 2.2.0 when building the binaries.
You might say it has no connection with Spring, however, I would argue that Spring does have noticeable weight in the ecosystem, and s3mock maintainer explicitly says: "they copy from Spring".
Here we are:
* Spring uses apiVersion=2.2, languageVersion=2.2
* Others copy what Spring does
* The ecosystem breaks with random failures like "binary version metadata is 2.2.0 expected version is 2.0.0"
Another infamous case relates to https://github.com/square/kotlinpoet
They also use apiVersion=latestKotlinVersionAvailable approach, and it causes multiple issues with mismatching metadata version across multiple years: https://github.com/square/kotlinpoet/issues?q=is%3Aissue%20state%3Aclosed%20%22compiled%20with%20an%20incompatible%20version%20of%20Kotlin%22
Comment From: vlsi
For reference, I tried building spring-framework with apiVersion=2.1 and languageVersion=2.1 and the build succeeds, so it looks like zero maintenance effort to target Kotlin 2.1.
As I tried building spring-framework with apiVersion=2.0 and languageVersion=2.0 the build does produce some warnings like the following:
w: spring-core/src/test/kotlin/org/springframework/core/ReactiveAdapterRegistryKotlinTests.kt:51:14
Java type mismatch: inferred type is 'Int?', but 'Int' was expected.
Note: it still won't impact the Spring users.
Some of the issues are caused by dubious nullability annotations. For instance, * https://github.com/spring-projects/spring-framework/blob/c08610ee58119b0ef39466fc4080ddbc4ec18fce/spring-tx/src/main/java/org/springframework/transaction/reactive/TransactionalOperator.java#L88 * https://github.com/spring-projects/spring-framework/blob/16edf9867a143f95cefadb7b2115dcbbf624e176/spring-tx/src/main/kotlin/org/springframework/transaction/reactive/TransactionalOperatorExtensions.kt#L48-L51
Java API does not permit nullable T while Kotlin API permits nullable T
Frankly, it sounds like a bug to me. The nullability treatment should be the same for both APIs.
If you intend non-nullable in Kotlin, you should go for <T: Any>.
If you intend nullable in Java, then you should go for <T extends @Nullable Object>
Comment From: sdeleuze
Sébastien, I never suggested using outdated Kotlin compiler. On contrary, I suggested using the latest Kotlin compiler. What I suggest is to target older Kotlin release with apiVersion, languageVersion and coreLibrariesVersion settings.
Spring would still use the latest and greatest Kotlin compiler, while the binaries could be consumed by a wider range of Kotlin clients.
A key point is that Spring Framework defines a baseline for the whole Spring ecosystem, not just for compiling Spring Framework itself. And here we want to enforce (not just document, because few users read the documentation) that projects consuming Spring Framework 7 dependencies are using Kotlin 2.2+ compiler.
I have no issues if Spring Boot application developers use Kotlin version they like. It should be the same as with Java versions, isn't it?
Some Spring Boot developers prefer using Java 17 even though it is not the very latest version.
Java and Kotlin compatibility and support policy are vastly different. Kotlin is is much more agressive in terms of the changes they do between minors, only support N-2 apiVersion/ languageVersion for a given compiler version (not even sure this is documented, this is a feedback we got from the Kotlin team), and even upgrading .10 to .20 patch releases can introduce pretty bold changes. Even the Kotlin major is not really a major from a semantic versioning POV as upgrading from Kotlin 1.x to 2.x was a switch to the K2 infrastructure with as few as possible language changes. Last point, as mentioned before, upgrading Java baseline requires forcing upgrading the JDK used to run the application, Kotlin baseline does not introduces such constraints.
Also, how we evaluate Java or Kotlin upgrades are evaluated on a case by case basis for each major, they are not following the same policy. For example, if Java 25 would have delivered null-restricted types, there is a good chance we would have raised the baseline to Java 25. In a potential future Spring Framework 8, it is not impossible we could be more agressive in terms of Java baseline upgrade than we will be for Kotlin.
The case is not directly related to Spring, but I have ran into it multiple times with various libraries that skip setting apiVersion, languageVersion, coreLibrariesVersion when building their Kotlin libraries.
...
You might say it has no connection with Spring, however, I would argue that Spring does have noticeable weight in the ecosystem, and s3mock maintainer explicitly says: "they copy from Spring".
Then please ask the s3mock maintainer (or kotlinpoet one) and other similar libraries to update their policy. The fact that library authors blindly copy Spring requirement or forget to set apiVersion/ languageVersion / coreLibrariesVersion to not raise the baseline when they upgrade Kotlin compiler/plugin version is IMO irrelevant to ask Spring to downgrade its baseline.
And to be clear, I totally understand your concern and ask that individual libraries uses a Kotlin 2.0 baseline if they don't have the same constraints that Spring. But the context and requirements of "any library usable in the JVM ecosystem" and "Spring integrating those libraries and using a Kotlin version across the portfolio including Spring Boot applications" are not the same.
Can you quantify the exact maintenance pain?
Not sure if maintenance pain is the right wording for what I meant, but given Spring adoption, I genuinely think that we would get a lot of confusion, invalid issues and even worst users using unsafe APIs without realizing a safe variant is available.
Correct me if I am wrong, but apiVersion=2.0, languageVersion=2.0, coreLibrariesVersion=2.0 does not result in platform types in Spring APIs. It would just ensure the resulting binaries are consumable with Kotlin 2.0, however, you could still use 2.2 compiler to get the latest bugfixes and so on.
Consuming Spring binaries with Kotlin 2.0 would result in platform type if you don't customize the configuration, we want to enforce it does not happen. We want to have a single well-defined baseline for the whole Spring portfolio, from Spring Framework to Spring Boot, from libraries to applications.
For reference, I tried building spring-framework
Thanks for the exploration work, but the baseline needs to be approach from a fullstack perspective, not just compiling Spring Framework. And JSpecify is not the only reason for that baseline, this is also related to defaults when no use-site targets are specified, to the desire to switch to Kotlin 2.4 (while keeping a Kotlin 2.2 baseline) in Spring Framework 7.1 to allow generating Java 25 bytecode, etc. What I mean is that this is not something we decided lightly, there is a lot of reasons that cumulated make the choice of a Kotlin 2.2 baeline the best solution from my POV.
Java API does not permit nullable T while Kotlin API permits nullable T Frankly, it sounds like a bug to me. The nullability treatment should be the same for both APIs.
Good catch, looks like a bug to me too, could you please please a dedicated issue?
Comment From: vlsi
Consuming Spring binaries with Kotlin 2.0 would result in platform type
It is clients' choice whether it wants upgrading Kotlin 2.0 to Kotlin 2.1, isn't it? What is the point of forcing every client upgrading their Kotlin compiler?
Comment From: afranken
@vlsi
and s3mock maintainer explicitly says: "they copy from Spring".
well, we use Spring as a dependency, import the dependency management etc. So I don't just "copy from Spring", I'm following their lead, and benefit from them (and all projects depending on Spring libraries) testing various dependency combinations with Java and Kotlin.
@sdeleuze
Then please ask the s3mock maintainer (or kotlinpoet one) and other similar libraries to update their policy. The fact that library authors blindly copy Spring requirement or forget to set apiVersion/ languageVersion / coreLibrariesVersion to not raise the baseline when they upgrade Kotlin compiler/plugin version is IMO irrelevant to ask Spring to downgrade its baseline.
While I could use different versions than Spring Framework or Spring Boot, I won't because I don't have the time to test different combinations. See above, using the same versions / settings is super helpful in reducing the amount of work for me as a client of the Spring Framework & Spring Boot. Thank you! :)
A key point is that Spring Framework defines a baseline for the whole Spring ecosystem, not just for compiling Spring Framework itself. And here we want to enforce (not just document, because few users read the documentation) that projects consuming Spring Framework 7 dependencies are using Kotlin 2.2+ compiler.
what is the policy going forward? :) Kotlin 2.3.0 was just released: https://blog.jetbrains.com/kotlin/2025/12/kotlin-2-3-0-released/
Comment From: vlsi
@sdeleuze , now I am directly impacted by Spring's apiVersion=2.2 as it is a transitive dependency of s3mock.
what is the policy going forward? :)
Frankly, I would love the policy to be "target the minimal Kotlin version which is reasonably easy to support". For instance, targeting Kotlin 2.1 requires no changes in Spring Framework code, and I guess it could be relatively easy to support.
Kotlin 2.3.0 was just released:
Kotlin 2.2.0 supports target 2.1, so it could be possible to use 2.3 compiler with 2.1 target.
Comment From: sdeleuze
what is the policy going forward? :) Kotlin 2.3.0 was just released: https://blog.jetbrains.com/kotlin/2025/12/kotlin-2-3-0-released/
I expect Spring Boot 4.1 will leverage Kotlin 2.3 while retaining a Kotlin 2.2 baseline, and I expect Spring Framework 7.1 / Spring Boot 4.2 will leverage Kotlin 2.4 while also retaining a Kotlin 2.2 baseline, following the same policy that we have applied since Kotlin support has been introduced.
Comment From: sdeleuze
I have shared some Kotlin baseline guidelines in https://spring.io/blog/2025/12/18/next-level-kotlin-support-in-spring-boot-4#kotlin-2-baseline both for libraries depending on Spring and those who do not.
@vlsi Hopefully that will help convincing authors of libraries not depending on Spring and not using JSpecify to chose a more lenient Kotlin 2.0 baseline. But of course, the choice of the baseline needs to be decided by each library author based on their context, maintenance strategy, etc.
Comment From: vlsi
@sdeleuze , thanks for putting all this. However, remember that clients can't use lower apiVersion than the one of Spring's.
In other words, they can't depend on Spring 7.0 and use apiVersion=2.1 as 7.0 uses apiVersion=2.2
It is not like "every library can select whatever they want", but they just can't use 2.0 if they have Spring among dependencies.
It is the same thing as with Java: if Spring targets Java 17, then libraries can't target Java 8 if they have Spring among the dependencies.
Hope Spring would refrain from "target the latest version available" in the future, and it would provide users some time for the migration.
Comment From: afranken
@vlsi
Hope Spring would refrain from "target the latest version available" in the future, and it would provide users some time for the migration.
I can't speak for the Spring team (or anyone else, really), but Kotlin 2.0 was released in May 2024, 2.1 in in May 2024, 2.2 in June 2025.
Projects still targeting 2.0 haven't updated their baseline in 18 months.
As a maintainer of an open-source library, I merge dependency updates almost every week. No open source project should break customer integrations without reason, but customers also can't expect every project to target old versions years after newer versions were released...
Comment From: vlsi
I can't speak for the Spring team (or anyone else, really), but Kotlin 2.0 was released in May 2024, 2.1 in in May 2024, 2.2 in June 2025. Projects still targeting 2.0 haven't updated their baseline in 18 months
Please see https://github.com/spring-projects/spring-framework/issues/34453#issuecomment-3660172146
Spring targets Java 17 which is 4 years old.
As a maintainer of an open-source library, I merge dependency updates almost every week.
Which Java version do you target? Frankly, I doubt you target Java 25.