These libraries ship inside Elide and need no download. Which ones are on a classpath by default is listed in JVM APIs.
| Library | Version | Kotlin file | Kotlin project | Switch |
|---|---|---|---|---|
| kotlinx.coroutines | 1.11.0 | Yes | Yes | kotlin. |
| kotlinx.serialization (core, JSON) | 1.11.0 | Yes | Yes | kotlin. |
| kotlinx-datetime | 0.8.0-0.6.x-compat | Yes | Declare | — |
| kotlinx-io (core, bytestring) | 0.9.1 | Yes | Declare | — |
| kotlinx-collections-immutable | 0.5.2 | Yes | Declare | — |
| kotlinx-html | 0.12.0 | Yes | Declare | — |
| atomicfu | 0.33.0 | Yes | Yes | kotlin. |
| Metro | 1.4.5 | No | Yes | kotlin.features.metro |
| JUnit (Jupiter, Platform) | 6.1.3 | — | Test sets | jvm.features.testing |
kotlin.test | 2.5.0-Beta1 | — | Test sets | kotlin.features.testing |
| kotlinx-coroutines-test | 1.11.0 | — | Test sets | kotlin. |
kotlin.features.kotlinx = false turns off coroutines and serialization together. JUnit’s switch is
jvm.features.testing; setting it to false removes the bundled JUnit, and JVM test runs then need junit-platform-console in testPackages. All Kotlin switches:
Kotlin compiler.
kotlin {
features {
serialization = false
}
}kotlinx.coroutines
// Fetch.kt
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
suspend fun load(name: String, ms: Long): Int {
delay(ms)
println("loaded $name")
return name.length
}
fun main() = runBlocking {
val sizes = listOf("users" to 300L, "orders" to 200L, "prices" to 100L)
.map { (name, ms) -> async { load(name, ms) } }
.awaitAll()
println("sizes in request order: $sizes")
}elide run Fetch.ktloaded prices
loaded orders
loaded users
sizes in request order: [5, 6, 6]kotlinx.serialization
The serialization compiler plugin is on with the runtime, so @Serializable classes need no setup.
// Config.kt
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class Server(val host: String, val port: Int = 8080, val tags: List<String> = emptyList())
fun main() {
val json = Json { prettyPrint = true }
val server = json.decodeFromString<Server>("""{"host": "localhost", "tags": ["dev"]}""")
println(server)
println(json.encodeToString(server.copy(port = 9090)))
}elide run Config.ktServer(host=localhost, port=8080, tags=[dev])
{
"host": "localhost",
"port": 9090,
"tags": [
"dev"
]
}Other kotlinx libraries
A Kotlin file run on its own can import every kotlinx library marked Yes under “Kotlin file” in the table:
// Extras.kt
import kotlinx.atomicfu.atomic
import kotlinx.collections.immutable.persistentListOf
import kotlinx.datetime.DatePeriod
import kotlinx.datetime.LocalDate
import kotlinx.datetime.plus
import kotlinx.html.p
import kotlinx.html.stream.createHTML
private val n = atomic(1)
fun main() {
n.incrementAndGet()
println(n.value)
println(persistentListOf(1, 2).add(3))
println(LocalDate(2026, 10, 11) + DatePeriod(days = 30))
println(createHTML().p { +"hi" }.trim())
}elide run Extras.kt2
[1, 2, 3]
2026-11-10
<p>hi</p>A project declares them. At the bundled version, elide install links the bundled JAR instead of downloading it:
// elide.pkl
amends "elide:project.pkl"
name = "dates"
jvm {
main = "MainKt"
}
dependencies {
maven {
packages { "org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.8.0-0.6.x-compat" }
}
}// src/main/kotlin/Main.kt
import kotlinx.datetime.DatePeriod
import kotlinx.datetime.LocalDate
import kotlinx.datetime.plus
fun main() {
println(LocalDate(2026, 10, 11) + DatePeriod(days = 30))
}elide run2026-11-10atomicfu is the exception: atomicfu-jvm is bundled whenever the atomicfu plugin is on (kotlin.features.atomicfu).
Metro
Metro generates dependency injection code at compile time. Kotlin projects get its compiler plugin and runtime; Kotlin files run on their own do not. Metro’s own documentation is at zacsweers.github.io/metro.
// elide.pkl
amends "elide:project.pkl"
name = "metro-demo"
jvm {
main = "MainKt"
}// src/main/kotlin/Main.kt
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.DependencyGraph
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Provides
import dev.zacsweers.metro.createGraph
interface Greeter {
fun greet(name: String): String
}
@Inject
class Polite(private val punctuation: String) : Greeter {
override fun greet(name: String) = "Hello, $name$punctuation"
}
@DependencyGraph(AppScope::class)
interface AppGraph {
val greeter: Greeter
@Binds val Polite.bind: Greeter
@Provides fun punctuation(): String = "!"
}
fun main() {
println(createGraph<AppGraph>().greeter.greet("Ada"))
}elide runHello, Ada!JUnit and kotlin.test
Test sets in Java and Kotlin projects get JUnit Jupiter (org.junit.jupiter.api, org.junit.jupiter.params) and the
JUnit Platform that elide test runs them on. Kotlin test sets also get kotlin.test and kotlinx-coroutines-test.
Test sets see the main set’s libraries too. Running tests: Testing.
// elide.pkl
amends "elide:project.pkl"
name = "slugs"// src/main/java/app/Slugs.java
package app;
public class Slugs {
public static String slugify(String text) {
return text.trim().toLowerCase().replaceAll("[^a-z0-9]+", "-").replaceAll("(^-|-$)", "");
}
}// src/test/java/app/SlugsTest.java
package app;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
class SlugsTest {
@ParameterizedTest
@CsvSource({"Hello World,hello-world", "' Elide 1.0 ',elide-1-0"})
void slugifies(String input, String expected) {
assertEquals(expected, Slugs.slugify(input));
}
}elide testapp.SlugsTest > slugifies(String, String)
✓ [1] input = "Hello World", expected = "hello-world" [120ms]
✓ [2] input = " Elide 1.0 ", expected = "elide-1-0" [4ms]
2 pass
0 skip
0 fail
Ran 2 tests across one file. (4.94s)kotlinx-coroutines-test runs suspending tests on virtual time:
// src/test/kotlin/DelayTest.kt
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
class DelayTest {
@Test fun skipsDelays() = runTest {
delay(60_000)
assertEquals(60_000, testScheduler.currentTime)
}
}DelayTest
✓ skipsDelays() [923ms]