This guide demonstrates how to create a Kotlin library targeted for the JVM. We’ll build a simple API with documentation, write and run tests, and package it all up into a something we can distribute.

It makes sense to use Gradle’s Kotlin DSL for build scripts since our library and tests are also in Kotlin.

What you’ll build

You’ll create a Kotlin library with the conventional layout, add a test to verify behavior, generate documentation, and publish the library with docs and sources.

If you get stuck at any point, you can check out the completed example.

What you’ll need

Step 1: Bootstrap Kotlin project

Let’s develop the simplest of libraries with just one API class and method.

Create project directory

This is the conventional layout for a Kotlin project. Luckily, Gradle is flexible and would allow us to easily change it by adjusting the sourceSets {}. We won’t worry about that today, though.

Kotlin project structure
├── build.gradle.kts
└── src
    ├── main
    │   └── kotlin
    │       └── org
    │           └── example
    │               └── MyLibrary.kt
    └── test
        └── kotlin
            └── org
                └── example
                    └── MyLibraryTest.kt

The first step is to create a folder for the new project and change directory into it. In a *nix shell this would be:

$ mkdir -p my-kotlin-library/src/main/kotlin/org/example
$ cd my-kotlin-library

In our new directory we add our library class called MyLibrary that returns a value object Language.

package org.example

 * The `Language` type defines a programming language with a name and hotness score.
 * @property name The name of the language.
 * @property hotness A score from 1 to 10 of user enthusiasm. 10 = so hot right now
data class Language(val name: String, val hotness: Int)

class MyLibrary {
     * @return data relating to the Kotlin {@code Language}.
    fun kotlinLanguage() = Language("Kotlin", 10)

With the following simple build script we can compile our new Kotlin library.

plugins {
    kotlin("jvm") version "1.3.61" (1)

repositories {
    jcenter() (2)

dependencies {
    implementation(kotlin("stdlib")) (3)
1 Apply the Kotlin plugin, targeting the Java VM
2 Declare a dependency repository on Bintray jcenter
3 Declare a dependency on the Kotlin standard library

We use the implementation dependency configuration so that we don’t expose any of the Kotlin standard library through our API. This has architectural and performance benefits.

We’re nearly ready to start testing and packaging our software.

Step 2: Add testing with JUnit

JUnit 4 is the simplest of testing libraries to add to our project. If you happen to prefer the Spek framework for Kotlin-based specifications, check out the Spek docs.

dependencies {
     implementation(kotlin("stdlib", "1.2.31"))
+    testImplementation("junit:junit:4.12") (1)
1 Add test implementation dependency on JUnit

Now we are ready to add tests for our library. We will follow the Kotlin plugin conventions and put them under src/test/kotlin.

package org.example

import org.junit.Assert.assertEquals
import org.junit.Test

class MyLibraryTest {
    @Test fun testMyLanguage() {
        assertEquals("Kotlin", MyLibrary().kotlinLanguage().name)
        assertEquals(10, MyLibrary().kotlinLanguage().hotness)

Nothing unexpected here. Now let’s run them.

Execute tests
$ gradle test

> Task :compileKotlin
Using kotlin incremental compilation

> Task :compileTestKotlin
Using kotlin incremental compilation

3 actionable tasks: 3 executed

Boom. Tests.

Step 3: Add docs with Dokka

A library isn’t done until it’s documented. Dokka is a popular documentation engine for Kotlin projects. Let’s use it.

Apply the Dokka plugin

We can declare the Dokka plugin in our plugins {} block:

    id("org.jetbrains.dokka") version "0.10.0"

Configure Dokka plugin

Now we can add configuration down below in our build script.

tasks.dokka {    (1)
    outputFormat = "html"
    outputDirectory = "$buildDir/javadoc"
1 Configure existing Dokka task to output HTML to typical Javadoc directory

There are many more configuration options available for Dokka, documented here, but this gets the job done for us right now. Let’s run it.

Generate docs with Dokka
$ gradle dokka

> Task :dokka
No documentation for org.example.MyLibrary (MyLibrary.kt:11)
No documentation for org.example.MyLibrary$<init>() (MyLibrary.kt:11)

1 actionable task: 1 executed

Dokka complains that we didn’t document absolutely everything, but there’s enough to get this if we open up $PROJECT_DIR/build/javadoc/my-kotlin-library/index.html. Click on the Language type and you should see our nice documentation.


Generate javadoc JAR

import org.gradle.jvm.tasks.Jar

val dokkaJar by tasks.creating(Jar::class) { (1)
    group = JavaBasePlugin.DOCUMENTATION_GROUP
    description = "Assembles Kotlin docs with Dokka"
    classifier = "javadoc"
    from(tasks.dokka) (2)
1 Create dokka Jar task from dokka task output
2 dependsOn(dokka) not needed; dependency automatically inferred by from(dokka)

Try running gradle dokkaJar and see if you can find the javadoc JAR based on what you know so far.

We could optionally also generate a "sources" JAR using the same pattern from java.sourceSets["main"].allSource.

Step 4: Publish to local repo

Now our library is ready to share with the world. We’re going to publish it locally with the maven-publish plugin just to keep things simple, but another popular choice is the Gradle Bintray Plugin. Their documentation has several samples you can use if you’re interested.

Apply the maven-publish plugin

plugins {
+    `maven-publish`
     kotlin("jvm") version "1.2.31"

Set project coordinates

Let us specify our project coordinates as org.example:my-kotlin-library:0.0.1 in our build script for publishing.

group = "org.example"
version = "0.0.1"

The project name is set by the root project directory name by default, but it is best practice to make it explicit. This is done in a settings.gradle.kts file at the project root.

settings.gradle.kts = "my-kotlin-library"

Configure Maven publication

For the maven-publish plugin to have any effect, a MavenPublication must be added to the set of publications. This publication determines which artifacts are actually published as well as the details included in the associated POM file.

publishing {
    publications {
        create<MavenPublication>("default") { (1)
            artifact(dokkaJar) (2)
    repositories {
        maven {
            url = uri("$buildDir/repository") (3)
1 Create a Maven publication called "default" from the "java" component
2 Declare the javadoc JAR from Dokka as an artifact
3 Declare a local Maven repository under the build/ directory

Now we are ready to publish!

Publish to local repository
$ gradle publish

> Task :dokka
No documentation for org.example.MyLibrary (MyLibrary.kt:11)
No documentation for org.example.MyLibrary$<init>() (MyLibrary.kt:11)

> Task :compileKotlin
Using kotlin incremental compilation

Could not find metadata org.example:my-kotlin-library/maven-metadata.xml in remote (file:$PROJECT_DIR/build/repository)

7 actionable tasks: 7 executed

Your Maven repository should now have the published artifacts.

Local Maven repository
└── org
    └── example
        └── my-kotlin-library
            ├── 0.0.1
            │   ├── my-kotlin-library-0.0.1-javadoc.jar
            │   ├── my-kotlin-library-0.0.1-javadoc.jar.md5
            │   ├── my-kotlin-library-0.0.1-javadoc.jar.sha1
            │   ├── my-kotlin-library-0.0.1.jar
            │   ├── my-kotlin-library-0.0.1.jar.md5
            │   ├── my-kotlin-library-0.0.1.jar.sha1
            │   ├── my-kotlin-library-0.0.1.pom
            │   ├── my-kotlin-library-0.0.1.pom.md5
            │   └── my-kotlin-library-0.0.1.pom.sha1
            ├── maven-metadata.xml
            ├── maven-metadata.xml.md5
            └── maven-metadata.xml.sha1

Congratulations! You’ve successfully built a Kotlin library, tested it, documented it, and packaged it as a JAR with docs and sources. The complete sample project is on GitHub.

Next Steps

We hope you found this fun and enlightening. Let us know what you thought of this guide via @gradle on Twitter.

Help improve this guide

Have feedback or a question? Found a typo? Like all Gradle guides, help is just a GitHub issue away. Please add an issue or pull request to gradle/guides and we’ll get back to you.