Question
Fix compileJava and compileKotlin JVM Target Mismatch in Gradle Kotlin DSL
Question
In a build.gradle.kts file, how can you configure the compileJava task and the compileKotlin task to use the same JVM target version?
For example, this Gradle script produces an error saying that Java is targeting version 11 while Kotlin is targeting 1.8:
buildscript {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath("com.android.tools.build:gradle:7.0.2")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30")
classpath("gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:${Versions.spotbugsGradlePluginVersion}")
classpath("se.bjurr.violations:violations-gradle-plugin:${Versions.violationsVersion}")
}
}
plugins {
`maven-publish`
`java-gradle-plugin`
`kotlin-dsl`
id("io.gitlab.arturbosch.detekt") version "1.18.1"
}
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
compileOnly(gradleApi())
testImplementation(gradleTestKit())
testImplementation("junit:junit:${Versions.jUnitVersion}")
}
val generatedSources = tasks.register<GenerateVersionsFileTask>("generateSources")
The error is:
'compileJava' task (current target is 11) and 'compileKotlin' task (current target is 1.8) jvm target compatibility should be set to the same Java version.
If you try to fix it by adding an android {} block, Gradle reports:
Unresolved reference: android
Why does this happen, and what is the correct way to set the Java and Kotlin target versions in this kind of Gradle project?
Short Answer
By the end of this page, you will understand why Gradle reports a JVM target mismatch between Java and Kotlin, why android {} is not available in every project, and how to correctly configure Java and Kotlin compilation targets in a non-Android build.gradle.kts file.
Concept
The core issue is that Java compilation and Kotlin compilation are configured separately in Gradle.
In many projects, Gradle creates:
- a
compileJavatask for Java source files - a
compileKotlintask for Kotlin source files
Both tasks generate JVM bytecode. If one task targets Java 11 and the other targets Java 8 (1.8), Gradle warns or fails because the outputs are inconsistent.
Why this matters
If Kotlin produces Java 8-compatible bytecode but Java produces Java 11-compatible bytecode, you can run into:
- incompatible class files
- confusing runtime behavior
- build tool validation errors
- harder-to-debug CI failures
Why android {} does not work here
The android {} block only exists in projects that apply an Android plugin such as:
com.android.applicationcom.android.library
Your script applies these plugins instead:
java-gradle-pluginkotlin-dslmaven-publish
Mental Model
Think of your build as a factory with two machines making parts for the same product:
- one machine compiles Java
- the other compiles Kotlin
If one machine makes parts sized for version 11 and the other makes parts sized for version 8, the final product may not fit together properly.
The android {} block is like a control panel that only exists in an Android factory. If you are in a plain JVM or Gradle plugin factory, that control panel simply is not installed.
Syntax and Examples
To fix the mismatch in a non-Android Gradle Kotlin DSL project, configure Java and Kotlin directly.
Option 1: Configure Java and Kotlin targets explicitly
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`maven-publish`
`java-gradle-plugin`
`kotlin-dsl`
id("io.gitlab.arturbosch.detekt") version "1.18.1"
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "11"
}
}
What this does
java {}sets Java source and target compatibility to Java 11tasks.withType<KotlinCompile>()updates all Kotlin compile tasksjvmTarget = "11"tells Kotlin to generate Java 11-compatible bytecode
Option 2: Configure Java compile tasks directly
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.gradle.api.tasks.compile.JavaCompile
tasks.withType<JavaCompile>().configureEach {
sourceCompatibility = "11"
targetCompatibility = "11"
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "11"
}
This is useful if you want to configure tasks directly instead of using the java extension.
Example of the mismatch
Step by Step Execution
Consider this configuration:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "11"
}
Here is what happens step by step:
- Gradle loads the plugins in the
pluginsblock. - Because this is a JVM/Gradle-plugin project, Gradle creates Java-related tasks such as
compileJava. - The Kotlin plugin creates Kotlin-related tasks such as
compileKotlin. - The
java {}block tells Gradle that Java source code should be compiled for Java 11. - The
tasks.withType<KotlinCompile>()block finds every Kotlin compilation task. kotlinOptions.jvmTarget = "11"tells Kotlin to emit Java 11 bytecode.- When Gradle validates the build, both tasks now agree on version 11.
- The mismatch error disappears.
Small trace example
java {
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "11"
}
compileJavatarget ->11
Real World Use Cases
Matching JVM targets is important in many real projects.
Common situations
- Spring Boot apps: Java and Kotlin classes live in the same codebase and must compile to the same target.
- Gradle plugins: Like your example, plugin code often mixes Java APIs and Kotlin build logic.
- Libraries published to Maven: Consumers expect consistent bytecode compatibility.
- Backend services: CI pipelines may run strict compatibility checks.
- Shared utility modules: Teams often use both Java and Kotlin in the same module.
Practical example
A backend service may use:
- Kotlin for service logic
- Java for legacy utilities
- Java 11 runtime in production
If Kotlin emits Java 8 bytecode but Java emits Java 11 bytecode, builds may still compile partially but fail validation or create confusing compatibility expectations for downstream users.
Real Codebase Usage
In real projects, developers usually solve this in one of these ways.
1. Set project-wide defaults
Teams often configure Java and Kotlin targets once near the top of the build file so every compile task stays consistent.
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "11"
}
2. Use guard rails in multi-module builds
In larger codebases, teams apply the same settings in a shared convention plugin or root Gradle script to avoid drift between modules.
3. Align with runtime requirements
If production runs on Java 17, the build is usually configured so both Java and Kotlin target 17.
4. Validation and CI stability
A consistent JVM target avoids CI-only failures where one environment is stricter than a developer machine.
5. Prefer explicit configuration
Even when defaults seem correct, many teams set the target explicitly to make the build predictable and self-documenting.
Common Mistakes
Here are the most common beginner mistakes.
Mistake 1: Using android {} in a non-Android project
Broken example:
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
Why it fails:
android {}only exists when an Android plugin is applied.- Your project uses JVM/Gradle-plugin plugins, not Android plugins.
How to avoid it:
- Use
java {}and Kotlin compile task configuration instead.
Mistake 2: Setting only Java and forgetting Kotlin
Broken example:
java {
targetCompatibility = JavaVersion.VERSION_11
}
Why it fails:
- Kotlin may still default to
1.8.
Fix:
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "11"
}
Mistake 3: Setting only Kotlin and forgetting Java
Broken example:
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.jvmTarget =
}
Comparisons
| Configuration approach | Where it works | Good for | Notes |
|---|---|---|---|
android { compileOptions {} kotlinOptions {} } | Android modules only | Android apps and libraries | Requires com.android.application or com.android.library |
java { sourceCompatibility targetCompatibility } | JVM Java projects | Standard Java/JVM setup | Good for compileJava settings |
tasks.withType<KotlinCompile>() | Kotlin JVM projects | Kotlin compile settings | Used to set kotlinOptions.jvmTarget |
tasks.withType<JavaCompile>() |
Cheat Sheet
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "11"
}
Rules
compileJavaandcompileKotlinshould target the same JVM version.- Use
android {}only in Android modules. - Use
java {}in standard JVM projects. - Use
tasks.withType<KotlinCompile>()to configure Kotlin compilation.
Quick checks
- Java target is
11-> KotlinjvmTargetshould be"11" - Java target is
1.8-> KotlinjvmTargetshould be"1.8" - Java target is
17-> KotlinjvmTargetshould be"17"
Common error meanings
FAQ
Why is android {} unresolved in build.gradle.kts?
Because the Android plugin is not applied. That block only exists in Android modules.
How do I fix Java 11 vs Kotlin 1.8 target mismatch?
Set Java compatibility to 11 and Kotlin jvmTarget to "11" in the same module.
Is buildscript {} the place to set JVM target versions?
No. buildscript {} is for build dependencies, not your source compilation target settings.
What should I use in a Gradle plugin project?
Use java {} for Java settings and tasks.withType<KotlinCompile>() for Kotlin settings.
Can Kotlin default to 1.8 even if Java uses 11?
Yes. That is why explicit Kotlin configuration is often needed.
Should sourceCompatibility and targetCompatibility both be set?
Usually yes, especially for clarity and consistent compilation behavior.
Can I use task configuration instead of java {}?
Yes. tasks.withType<JavaCompile>() and also work.
Mini Project
Description
Create a small Gradle JVM project configuration that compiles Java and Kotlin code to the same JVM version. This demonstrates how to avoid target mismatch errors in mixed-language builds.
Goal
Configure a Gradle Kotlin DSL project so both Java and Kotlin compile for Java 11 without using an android {} block.
Requirements
- Apply JVM-compatible plugins, not Android plugins.
- Set Java source and target compatibility to version 11.
- Set Kotlin
jvmTargetto"11". - Keep the configuration in
build.gradle.kts. - Do not use an
android {}block.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.
Android Foreground Service Notification Channels in Kotlin
Learn why startForeground fails on Android 8.1 and how to create a valid notification channel for foreground services in Kotlin.