Question

Fix compileJava and compileKotlin JVM Target Mismatch in Gradle Kotlin DSL

kotlinjavaandroid-gradle-plugindependenciesgradle-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 compileJava task for Java source files
  • a compileKotlin task 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.application
  • com.android.library

Your script applies these plugins instead:

  • java-gradle-plugin
  • kotlin-dsl
  • maven-publish

So this is not an Android module. It is a Gradle plugin / JVM project. That is why Gradle says:

Unresolved reference: android

The real fix

For a JVM project, configure:

  • Java using the java extension or Java compile tasks
  • Kotlin using kotlinOptions.jvmTarget or newer Kotlin JVM toolchain settings

The important rule is simple:

Java target version and Kotlin JVM target must match.

If Java is 11, Kotlin should also target 11.

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.

Take Quiz

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 11
  • tasks.withType<KotlinCompile>() updates all Kotlin compile tasks
  • jvmTarget = "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

tasks.withType<JavaCompile>().configureEach {
    targetCompatibility = "11"
}

tasks.withType<KotlinCompile>().configureEach {
    kotlinOptions.jvmTarget = "1.8"
}

This causes the same kind of problem because the two compilers target different JVM versions.

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:

  1. Gradle loads the plugins in the plugins block.
  2. Because this is a JVM/Gradle-plugin project, Gradle creates Java-related tasks such as compileJava.
  3. The Kotlin plugin creates Kotlin-related tasks such as compileKotlin.
  4. The java {} block tells Gradle that Java source code should be compiled for Java 11.
  5. The tasks.withType<KotlinCompile>() block finds every Kotlin compilation task.
  6. kotlinOptions.jvmTarget = "11" tells Kotlin to emit Java 11 bytecode.
  7. When Gradle validates the build, both tasks now agree on version 11.
  8. The mismatch error disappears.

Small trace example

java {
    targetCompatibility = JavaVersion.VERSION_11
}

tasks.withType<KotlinCompile>().configureEach {
    kotlinOptions.jvmTarget = "11"
}
  • compileJava target -> 11
  • compileKotlin target -> 11
  • Result -> compatible build output

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.

Take Quiz

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 = "11"
}

Why it fails:

  • Java tasks may still target a different version.

Fix:

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

Mistake 4: Using "1.8" for Kotlin and 11 for Java

Broken example:

java {
    targetCompatibility = JavaVersion.VERSION_11
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
    kotlinOptions.jvmTarget = "1.8"
}

How to avoid it:

  • Make both values represent the same version.

Mistake 5: Assuming buildscript {} controls compile targets

The buildscript {} block configures dependencies needed to run the build itself. It does not automatically set your Java and Kotlin bytecode target versions.

Comparisons

Configuration approachWhere it worksGood forNotes
android { compileOptions {} kotlinOptions {} }Android modules onlyAndroid apps and librariesRequires com.android.application or com.android.library
java { sourceCompatibility targetCompatibility }JVM Java projectsStandard Java/JVM setupGood for compileJava settings
tasks.withType<KotlinCompile>()Kotlin JVM projectsKotlin compile settingsUsed to set kotlinOptions.jvmTarget
tasks.withType<JavaCompile>()JVM Java projectsTask-level Java configMore explicit, useful in custom setups

android {} vs java {}

Featureandroid {}java {}
Available in Android projectYesSometimes, depending on plugins
Available in plain JVM/Gradle plugin projectNoYes
Used for Android SDK configYesNo
Used for Java compatibility in JVM projectsNoYes

Kotlin jvmTarget values

ValueMeaning
"1.8"Java 8 bytecode
"11"Java 11 bytecode
"17"Java 17 bytecode

The important part is that Kotlin and Java should target the same level.

Take Quiz

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

  • compileJava and compileKotlin should 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 -> Kotlin jvmTarget should be "11"
  • Java target is 1.8 -> Kotlin jvmTarget should be "1.8"
  • Java target is 17 -> Kotlin jvmTarget should be "17"

Common error meanings

  • Unresolved reference: android -> no Android plugin applied
  • compileJava ... and compileKotlin ... should be set to the same Java version -> Java and Kotlin targets do not match

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 tasks.withType<KotlinCompile>() also work.

Take Quiz

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

  1. Apply JVM-compatible plugins, not Android plugins.
  2. Set Java source and target compatibility to version 11.
  3. Set Kotlin jvmTarget to "11".
  4. Keep the configuration in build.gradle.kts.
  5. Do not use an android {} block.
Take Quiz

Keep learning

Related questions

View more