# Kora Project Setup Kotlin

> Scaffold a new Kotlin Kora service (Gradle Kotlin DSL) — KSP symbol-processors, kora-parent BOM, koraBom, @KoraApp, wrapper. Use when starting a Kotlin project or configuring KSP. For Java see kora-project-setup-java.

- Skill: `kora-projects/kora-project-setup-kotlin` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add kora-projects/kora-project-setup-kotlin`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kora-projects/kora-project-setup-kotlin/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kora-projects (https://skillmd.com/u/kora-projects)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kora-projects/kora-project-setup-kotlin

---


# Kora Project Setup — Kotlin

> **Kora sub-skill — obey the [kora-v1 meta rules](../../SKILL.md) on every task:** **R0** ensure `.kora-agent/` docs+examples are cloned · **R1** read this sub-skill before writing code · **R2** Kora APIs only — no Spring/Micronaut/Quarkus, no invented annotations or config keys · **R3** journal any incorrect Kora usage. Add comments/Javadoc only if asked.

Scaffold a runnable Kotlin Kora service: Gradle Kotlin DSL build, KSP symbol
processors, the `kora-parent` BOM, and a `@KoraApp` interface that plugs in Kora
capabilities by extending `*Module` interfaces.

**Pinned versions** (match `.kora-agent/kora-examples`): Kora BOM `1.2.19`,
Kotlin `1.9.25`, KSP `1.9.25-1.0.20`, Gradle `9.5.1`, JVM toolchain `21`.
Never version individual `ru.tinkoff.kora:*` artifacts — the BOM aligns them all.

---

## Core principle

Kora generates code at compile time. For Kotlin this runs through **KSP** (the
`com.google.devtools.ksp` plugin + the `ru.tinkoff.kora:symbol-processors`
artifact), not Java's `annotationProcessor`. Without KSP, nothing is generated
and the build produces no `ApplicationGraph`. KSP writes generated sources to
`build/generated/ksp/main/kotlin` — register that directory as a source dir so
IDEs and compilation see it.

---

## Project structure

```
my-app/
├── build.gradle.kts
├── settings.gradle.kts
├── gradle.properties
├── gradle/wrapper/gradle-wrapper.properties
├── src/main/
│   ├── kotlin/com/example/Application.kt
│   └── resources/application.conf        # HOCON config
│   └── resources/logback.xml             # logging config
└── src/test/kotlin/com/example/
```

---

## Quick Start

### 1. settings.gradle.kts

The `foojay-resolver-convention` plugin lets the Java toolchain auto-download the
requested JDK instead of relying only on locally installed ones.

```kotlin
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}

rootProject.name = "kora-example"
```

### 2. build.gradle.kts

```kotlin
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JvmVendorSpec

plugins {
    id("application")
    kotlin("jvm") version "1.9.25"
    id("com.google.devtools.ksp") version "1.9.25-1.0.20"
}

repositories {
    mavenCentral()
}

// The koraBom configuration carries the BOM and feeds aligned versions into the
// real configurations. ksp needs it separately because it has its own classpath.
val koraBom: Configuration by configurations.creating
configurations {
    ksp.get().extendsFrom(koraBom)
    compileOnly.get().extendsFrom(koraBom)
    implementation.get().extendsFrom(koraBom)
    testImplementation.get().extendsFrom(koraBom)
    kspTest.get().extendsFrom(koraBom)
}

dependencies {
    koraBom(platform("ru.tinkoff.kora:kora-parent:1.2.19"))

    // Mandatory: the Kora symbol processors. Without them nothing is generated.
    ksp("ru.tinkoff.kora:symbol-processors")

    implementation("ru.tinkoff.kora:http-server-undertow")
    implementation("ru.tinkoff.kora:config-hocon")
    implementation("ru.tinkoff.kora:json-module")
    implementation("ru.tinkoff.kora:logging-logback")

    kspTest("ru.tinkoff.kora:symbol-processors")
    testImplementation("ru.tinkoff.kora:test-junit5")
}

kotlin {
    jvmToolchain {
        languageVersion.set(JavaLanguageVersion.of(21))
        vendor.set(JvmVendorSpec.ADOPTIUM)
    }
    sourceSets.main { kotlin.srcDir("build/generated/ksp/main/kotlin") }
    sourceSets.test { kotlin.srcDir("build/generated/ksp/test/kotlin") }
}

application {
    applicationName = "application"
    mainClass.set("com.example.ApplicationKt")
    applicationDefaultJvmArgs = listOf("-Dfile.encoding=UTF-8")
}

tasks.distTar {
    archiveFileName.set("application.tar")
}

tasks.test {
    useJUnitPlatform()
}
```

Full file: [`assets/build.gradle.kts.template`](assets/build.gradle.kts.template)

### 3. gradle.properties

```properties
org.gradle.java.installations.auto-detect=true
org.gradle.java.installations.auto-download=true
# Kotlin 1.9.25 cannot target every recent JDK exactly; warn instead of fail.
kotlin.jvm.target.validation.mode=warning
org.gradle.jvmargs=-Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
```

### 4. Application.kt

`@KoraApp` marks the application graph root. Each Kora capability is added by
extending its `*Module` interface. The `ApplicationGraph` object is generated by
KSP at compile time, so it does not resolve in the IDE until the first build.

```kotlin
package com.example

import ru.tinkoff.kora.application.graph.KoraApplication
import ru.tinkoff.kora.common.KoraApp
import ru.tinkoff.kora.config.hocon.HoconConfigModule
import ru.tinkoff.kora.http.server.undertow.UndertowHttpServerModule
import ru.tinkoff.kora.json.module.JsonModule
import ru.tinkoff.kora.logging.logback.LogbackModule

@KoraApp
interface Application :
    HoconConfigModule,
    JsonModule,
    LogbackModule,
    UndertowHttpServerModule

fun main() {
    KoraApplication.run { ApplicationGraph.graph() }
}
```

Full file: [`assets/Application.kt.template`](assets/Application.kt.template)

### 5. A first component

Components are registered with `@Component`; an HTTP controller adds
`@HttpController` and `@HttpRoute`. Adapted from
`.kora-agent/kora-examples/guides/kotlin/kora-kotlin-guide-getting-started-app`.

```kotlin
package com.example

import ru.tinkoff.kora.common.Component
import ru.tinkoff.kora.http.common.HttpMethod
import ru.tinkoff.kora.http.common.annotation.HttpRoute
import ru.tinkoff.kora.http.common.body.HttpBody
import ru.tinkoff.kora.http.server.common.HttpServerResponse
import ru.tinkoff.kora.http.server.common.annotation.HttpController

@Component
@HttpController
class HelloController {

    @HttpRoute(method = HttpMethod.GET, path = "/hello")
    fun hello(): HttpServerResponse =
        HttpServerResponse.of(200, HttpBody.plaintext("Hello, Kora!"))
}
```

### 6. application.conf (HOCON)

Keep public traffic and metrics/probes on separate ports.

```hocon
httpServer {
  publicApiHttpPort = 8080
  privateApiHttpPort = 8085
  telemetry.logging.enabled = true
}

logging.level {
  "root": "WARN"
  "ru.tinkoff.kora": "INFO"
}
```

### 7. Gradle wrapper

`gradle/wrapper/gradle-wrapper.properties`:

```properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
```

---

## Commands

```bash
./gradlew classes        # runs KSP; first real validation that the graph builds
./gradlew run            # starts the application
./gradlew clean build    # full build + tests
./gradlew test           # tests
```

`classes` is a meaningful check in Kora: it runs the symbol processors, so it
verifies not only Kotlin syntax but that the application graph can be assembled.

---

## When to use vs NOT

| Use this skill when | Do NOT use when |
|---|---|
| Starting a new Kotlin Kora service | Project is Java → use `kora-project-setup-java` |
| Wiring `build.gradle.kts`, KSP, the BOM, the wrapper | Adding modules to an existing Kora app → `kora-project-dependencies` |
| Splitting a service into Gradle modules with `@KoraSubmodule` | Configuring HOCON details → `kora-config-hocon` |

---

## Common pitfalls

| Symptom | Cause | Fix |
|---|---|---|
| `ApplicationGraph` unresolved | KSP never ran | Run `./gradlew classes`; ensure the `ksp(...)` dependency and the KSP plugin are present |
| IDE cannot see generated classes | KSP output dir not a source dir | Add `sourceSets.main { kotlin.srcDir("build/generated/ksp/main/kotlin") }` |
| "Required dependency not found" | A `*Module` not extended, or `@Component` missing | Extend the module on `@KoraApp`; annotate the class with `@Component` |
| Version conflicts on Kora artifacts | A `ru.tinkoff.kora:*` dep pinned manually | Remove the explicit version; let the BOM align it |
| Build hangs after `clean` | Stale Gradle daemon | `./gradlew --stop`, then retry |

---

## Multi-module / @KoraSubmodule

Most services are a single module. To split across Gradle modules with
`@KoraSubmodule` feature modules aggregated by a `@KoraApp` app module, see
[`references/multi-module-reference.md`](references/multi-module-reference.md).

---

## Assets

| File | Description |
|---|---|
| [`assets/build.gradle.kts.template`](assets/build.gradle.kts.template) | Single-module Kotlin build config |
| [`assets/settings.gradle.kts.template`](assets/settings.gradle.kts.template) | Settings with foojay toolchain resolver |
| [`assets/Application.kt.template`](assets/Application.kt.template) | `@KoraApp` root + `main()` |
| [`assets/gradle.properties`](assets/gradle.properties) | Gradle/Kotlin properties |
| [`assets/gradle-wrapper.properties`](assets/gradle-wrapper.properties) | Gradle wrapper config |

---

## Next steps

- [`kora-project-dependencies`](../kora-project-dependencies/SKILL.md) — add modules (HTTP, Database, Kafka, ...)
- [`kora-config-hocon`](../kora-config-hocon/SKILL.md) — typed `@ConfigSource` configuration
- [`kora-di-compile`](../kora-di-compile/SKILL.md) — compile-time DI patterns
- [`kora-testing-junit-kotlin`](../kora-testing-junit-kotlin/SKILL.md) — `@KoraAppTest` component tests

---

## References

| Document | Description |
|---|---|
| [`references/multi-module-reference.md`](references/multi-module-reference.md) | Gradle multi-module + `@KoraSubmodule` setup |
| [`bom-usage-reference.md`](../kora-project-dependencies/references/bom-usage-reference.md) | BOM setup details |
| [`compatibility-matrix.md`](../kora-project-dependencies/references/compatibility-matrix.md) | Version compatibility |
| [`core-modules-reference.md`](../kora-project-dependencies/references/core-modules-reference.md) | Core modules catalogue |

