Monorepository with Kotlin: Code Organization for Beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: What is a Monorepository and Why Does a Kotlin Developer Need It



A monorepository (monorepo) is an approach where the code of several projects or modules is stored in a single repository. In the context of Kotlin, this is especially convenient: you can combine a server-side part (Ktor), libraries, CLI tools, and even mobile applications (Kotlin Multiplatform) into a single structure. For beginner developers, a monorepository simplifies navigation, testing, and collaboration.



In this article, we will break down how to organize a monorepository with Kotlin using Gradle Multi-Project Build. You will learn how to properly structure folders, configure dependencies, and avoid common mistakes.



Main Part: Creating a Monorepository with Kotlin



1. Monorepository Structure: Basic Principles



A proper structure is the key to success. In a Kotlin monorepository, each module is a separate Gradle subproject. Here is a typical scheme:



my-monorepo/├── build.gradle.kts          # Root build file├── settings.gradle.kts       # Module configuration├── gradle.properties         # Common properties├── shared/                   # Shared library (module)│   ├── build.gradle.kts│   └── src/│       └── main/│           └── kotlin/│               └── com/example/shared/│                   └── Utils.kt├── backend/                  # Server module (Ktor)│   ├── build.gradle.kts│   └── src/│       └── main/│           └── kotlin/│               └── com/example/backend/│                   └── Application.kt└── cli-tool/                 # CLI tool    ├── build.gradle.kts    └── src/        └── main/            └── kotlin/                └── com/example/cli/                    └── Main.kt


Key rule: one module — one responsibility. Do not mix business logic and infrastructure in one module. This simplifies testing and code reuse.



2. Configuring Gradle for a Monorepository



Let's start with the root file settings.gradle.kts. It defines which modules are included in the project:



// settings.gradle.ktsrootProject.name = "my-monorepo"

include(":shared")include(":backend")include(":cli-tool")

// Optional: you can set module names via include()// include(":libs:utils") — if the module is nested in the libs folder


Now the root build.gradle.kts. It usually contains only common settings (plugins, repositories) and has no code of its own:



// build.gradle.kts (root)plugins {    kotlin("jvm") version "1.9.22" apply false    id("application") apply false}

allprojects { repositories { mavenCentral() }}

subprojects { apply(plugin = "kotlin") // Common settings for all subprojects dependencies { implementation(kotlin("stdlib")) }}


Note the apply false — this prevents applying the plugin to the root project. Each module decides which plugins it needs.



3. Module Example: Shared Library (shared)



The shared module will contain reusable functions. Its build.gradle.kts:



// shared/build.gradle.ktsplugins {    kotlin("jvm")}

dependencies { // No internal dependencies — this is a base module testImplementation("org.jetbrains.kotlin:kotlin-test")}


The code itself in Utils.kt:



// shared/src/main/kotlin/com/example/shared/Utils.ktpackage com.example.shared

fun greet(name: String): String = "Hello, $name!"

fun add(a: Int, b: Int): Int = a + b


Now this module can be connected to other modules:



// backend/build.gradle.ktsplugins {    kotlin("jvm")    id("application")}

dependencies { implementation(project(

Blogs

Book Recommendations