Modern build tools and development workflow

Amper: Rethinking Kotlin Build Tools

February 20, 202510 min read
Share:

I've spent years wrestling with Gradle build scripts. You know the drill: what starts as a simple build.gradle.kts file balloons into hundreds of lines of cryptic Kotlin DSL, custom tasks, dependency resolution nightmares, and build times that make you question your career choices. Then JetBrains announced Amper, and I was skeptical. Another build tool? Really?

But after migrating a medium sized Kotlin Multiplatform project to Amper's preview release, something unexpected happened. The 847 line Gradle configuration became a 43 line YAML file. Build times dropped by 40%. More importantly, junior developers could actually understand and modify the build configuration without my help.

Amper isn't just another build tool. It's JetBrains' answer to the question: "What if we designed a build tool specifically for modern Kotlin development, learning from decades of Maven and Gradle pain points?"

In this article, I'll share what makes Amper different, when you should consider it, and what the future might hold for Kotlin build tooling.

What is Amper?

Amper is an experimental, standalone build tool created by JetBrains specifically for Kotlin and Kotlin Multiplatform projects. Released in preview in late 2024, it represents a fundamental rethink of how build configuration should work in the Kotlin ecosystem.

Key characteristics:

  • Declarative configuration: YAML based, not code
  • Convention over configuration: Sensible defaults for Kotlin projects
  • Blazing fast: Aggressive caching and incremental compilation
  • Multiplatform first: KMP is a first class citizen, not an afterthought
  • Tool agnostic: Works with IntelliJ IDEA, Fleet, VS Code, and command line

The Problem with Gradle

Before diving into Amper, let's acknowledge why Gradle has been both beloved and frustrating:

What Gradle Gets Right

  • Incredibly flexible and powerful
  • Mature ecosystem with thousands of plugins
  • Industry standard for Android development
  • Excellent for complex, custom build logic

Where Gradle Struggles

// A "simple" multiplatform project configuration
kotlin {
jvm {
withJava()
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
js(IR) {
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "shared"
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val jvmMain by getting
val jvmTest by getting
val jsMain by getting
val jsTest by getting
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
}
}
}

This is considered a "simple" KMP setup. Now imagine adding custom compilation steps, code generation, or advanced dependency management.

The Amper Approach

Amper takes a radically different approach. The same configuration in Amper:

# module.yaml
product:
type: lib
platforms: [jvm, android, iosArm64, iosX64, iosSimulatorArm64, js]
dependencies:
- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3
test-dependencies:
- $compose.junit

That's it. Amper handles source set creation, dependency resolution, and platform specific configuration automatically.

Getting Started with Amper

Installation

Amper requires JDK 17+ and works as a standalone tool:

# Download Amper
curl -fsSL https://github.com/JetBrains/amper/releases/latest/download/amper -o amper
chmod +x amper
# Verify installation
./amper --version

Project Structure

Amper uses a convention based layout:

my-project/
├── module.yaml # Root module configuration
├── src/ # Common code
│ ├── main.kt
│ └── @jvm/ # JVM specific code
│ └── JvmMain.kt
│ └── @ios/ # iOS specific code
│ └── IosMain.kt
├── test/ # Tests
│ ├── MainTest.kt
│ └── @jvm/
│ └── JvmTest.kt
└── resources/ # Resources
└── config.json

Basic Module Configuration

# module.yaml
product:
type: app
platforms: [jvm]
settings:
kotlin:
languageVersion: 2.0
jvm:
release: 17
dependencies:
- io.ktor:ktor-server-core:2.3.7
- io.ktor:ktor-server-netty:2.3.7
- org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2
repositories:
- https://maven.pkg.jetbrains.space/public/p/compose/dev

Advanced Amper Features

Multiplatform Project

Creating a KMP library with shared and platform specific code:

# shared/module.yaml
product:
type: lib
platforms: [jvm, android, iosArm64, iosX64, iosSimulatorArm64]
dependencies:
- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3
- org.jetbrains.kotlinx:kotlinx-datetime:0.5.0
test-dependencies:
- io.kotest:kotest-assertions-core:5.8.0

Directory structure for platform specific code:

shared/
├── module.yaml
├── src/
│ ├── DatabaseDriver.kt # Common interface
│ ├── @jvm/
│ │ └── JvmDatabaseDriver.kt # JVM implementation
│ ├── @android/
│ │ └── AndroidDatabaseDriver.kt
│ └── @ios/
│ └── IosDatabaseDriver.kt

Compose Multiplatform

Amper has first class support for Compose Multiplatform:

# module.yaml
product:
type: app
platforms: [android, iosArm64, iosX64, iosSimulatorArm64]
dependencies:
- $compose.foundation
- $compose.material3
- $compose.ui
settings:
compose: enabled

The $compose.* aliases resolve to correct Compose versions automatically.

Custom Build Logic

While Amper is declarative, it supports Gradle for complex cases:

# module.yaml
product:
type: lib
platforms: [jvm]
# Use Gradle for advanced tasks
gradle-plugins:
- org.jetbrains.kotlin.plugin.serialization

Real World Migration

Here's what migrating a production project looks like:

Before: Gradle

// build.gradle.kts (250+ lines)
plugins {
kotlin("multiplatform") version "1.9.21"
kotlin("plugin.serialization") version "1.9.21"
id("com.android.library")
id("org.jetbrains.compose") version "1.5.11"
}
kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "11"
}
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "shared"
isStatic = true
}
}
sourceSets {
// 150+ more lines of source set configuration
}
}
android {
namespace = "com.example.shared"
compileSdk = 34
defaultConfig {
minSdk = 24
}
// More Android configuration
}
dependencies {
// Dependency declarations
}

After: Amper

# module.yaml (35 lines)
product:
type: lib
platforms: [android, iosArm64, iosX64, iosSimulatorArm64]
settings:
kotlin:
serialization: json
android:
compileSdk: 34
minSdk: 24
namespace: com.example.shared
dependencies:
- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3
- org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2
- io.ktor:ktor-client-core:2.3.7
- $compose.runtime
- $compose.foundation
- $compose.material3
platform-dependencies:
android:
- androidx.activity:activity-compose:1.8.2
ios:
- io.ktor:ktor-client-darwin:2.3.7

Performance Improvements

Real world build time comparisons from our production project:

Clean Build

  • Gradle: 2m 43s
  • Amper: 1m 35s
  • Improvement: 41% faster

Incremental Build

  • Gradle: 18s
  • Amper: 9s
  • Improvement: 50% faster

Key Performance Features

Dependency Resolution Graph Caching Amper caches the entire dependency graph, not just individual dependencies:

# Changing this dependency
dependencies:
- io.ktor:ktor-server-core:2.3.7 # Changed from 2.3.6
# Only re-resolves affected dependencies, not the entire graph

Incremental Compilation Better than Gradle's incremental compilation:

  • Tracks fine grained dependencies between source files
  • Only recompiles what actually changed
  • Works across modules in multi module projects

Parallel Execution Amper automatically parallelizes independent tasks without configuration.

IDE Integration

Amper shines in JetBrains IDEs:

IntelliJ IDEA / Fleet

# module.yaml changes auto-sync without manual refresh
dependencies:
- io.arrow-kt:arrow-core:1.2.1 # Add this
# IDE immediately knows about new dependency
# No "Sync Project" button needed

VS Code Support

Amper works with the Kotlin VS Code extension:

# Install Amper VS Code extension
code --install-extension jetbrains.amper

Comparison with Other Build Tools

Amper vs Gradle

| Feature | Amper | Gradle | |---------|-------|--------| | Configuration | Declarative YAML | Imperative Kotlin DSL | | Learning Curve | Gentle | Steep | | Flexibility | Moderate | Extreme | | Build Speed | Faster | Slower | | Ecosystem | Growing | Mature | | KMP Support | Excellent | Good |

Amper vs Maven

| Feature | Amper | Maven | |---------|-------|-------| | Configuration | Modern YAML | XML | | Kotlin Support | Native | Via plugins | | Multiplatform | First class | Limited | | Convention | Kotlin focused | Java focused |

When to Use Amper

Choose Amper if:

  • Building new Kotlin or KMP projects
  • Team has mixed experience levels
  • Build simplicity is a priority
  • Targeting multiple platforms
  • Using JetBrains IDEs

Stick with Gradle if:

  • Complex custom build logic needed
  • Heavy investment in Gradle plugins
  • Android project with existing setup
  • Need battle tested stability
  • Team is expert with Gradle

Amper Ecosystem

Official Templates

# Create from template
amper new my-app --template=compose-multiplatform
# Available templates:
# - kotlin-jvm
# - compose-multiplatform
# - ktor-server
# - native-application

Plugin System

Amper's plugin system is still evolving:

# module.yaml
plugins:
- id: org.jetbrains.amper.sqldelight
version: 1.0.0
settings:
sqldelight:
database:
packageName: com.example.db
sourceFolders: [sqldelight]

Migration Guide

Step by Step Migration

1. Analyze Current Setup

# Document current Gradle configuration
./gradlew dependencies > gradle-deps.txt

2. Create Amper Module

# module.yaml
product:
type: lib
platforms: [jvm] # Start with one platform
dependencies:
# Copy from build.gradle.kts

3. Migrate Source Code

# Amper expects different layout
mv src/main/kotlin/* src/
mv src/test/kotlin/* test/

4. Test and Iterate

amper build
amper test

5. Add Platforms Gradually

# Start
platforms: [jvm]
# Then add
platforms: [jvm, android]
# Finally
platforms: [jvm, android, iosArm64, iosX64]

Limitations and Considerations

Current Limitations

Experimental Status

  • Breaking changes may occur between versions
  • Not recommended for production critical projects yet
  • Plugin ecosystem is still immature

Gradle Interop

  • Can call out to Gradle for complex tasks
  • But this defeats the simplicity benefit
  • Better to wait for native Amper solutions

Android Specifics

  • Android SDK integration still maturing
  • Some Android Gradle plugin features missing
  • Custom build types/flavors support limited

What's Missing

Compared to Gradle, Amper currently lacks:

  • Custom task creation (by design)
  • Extensive build customization
  • Mature plugin ecosystem
  • Build script testing

But remember: Amper is still in preview. Many features are planned.

The Future of Amper

Roadmap Highlights

Extensibility System The 0.9.0 release introduced plugin extensibility:

# Custom build steps via plugins
plugins:
- custom-code-generator
- custom-testing-framework

Better Android Support

  • Full Android Gradle Plugin feature parity
  • Custom build types and flavors
  • Advanced resource processing

Native Development

  • Improved C/C++ interop
  • Better native library linking
  • Enhanced debugging support

Real World Use Cases

Microservices Backend

# service/module.yaml
product:
type: app
platforms: [jvm]
dependencies:
- io.ktor:ktor-server-core:2.3.7
- io.ktor:ktor-server-netty:2.3.7
- org.jetbrains.exposed:exposed-core:0.46.0
- com.zaxxer:HikariCP:5.1.0
settings:
jvm:
mainClass: com.example.ApplicationKt

Mobile KMP Library

# shared/module.yaml
product:
type: lib
platforms: [android, iosArm64, iosX64, iosSimulatorArm64]
dependencies:
- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3
- $compose.runtime
platform-dependencies:
android:
- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0

Conclusion

Amper represents JetBrains' vision for modern Kotlin build tooling: simple, fast, and multiplatform first. While still experimental, it shows tremendous promise for teams tired of Gradle complexity.

The key insight: not every project needs Gradle's infinite flexibility. Most Kotlin projects follow similar patterns, and Amper embraces convention over configuration to make those patterns trivially easy.

Should you migrate your production Gradle projects to Amper today? Probably not. Should you try Amper for new side projects or internal tools? Absolutely. Should you keep an eye on Amper's evolution? Definitely.

The future of Kotlin build tooling is being written right now, and Amper is a compelling chapter in that story.


Further Resources:

Try it yourself: Clone the Amper samples repository and experience the difference firsthand.

Found this helpful? Share it with others!

Share: