Skip to content

Getting started

This documentation assumes you already have a Compose Multiplatform project set up. If you haven’t already, follow the official JetBrains documentation to set up a project.

This library is published via Maven Central, and snapshot builds of main are additionally available from Central Portal Snapshots.

The latest release is v0.14.0. In your Gradle version catalog, add:

libs.versions.toml
[libraries]
maplibre-compose = { module = "org.maplibre.compose:maplibre-compose", version = "0.14.0" }

In your Gradle build script, add:

build.gradle.kts
commonMain.dependencies {
implementation(libs.maplibre.compose)
}

Maps use the application’s private cache directory.

Alongside the library, add a runtime: the native libraries for one render backend.

build.gradle.kts
androidMain {
dependencies {
runtimeOnly("org.maplibre.compose:maplibre-compose-runtime-opengl-android:0.14.0")
}
}

Available runtimes:

Render backendRuntime
OpenGLmaplibre-compose-runtime-opengl-android
Vulkanmaplibre-compose-runtime-vulkan-android

Match the runtime’s version to the library version you selected above, including when that is a snapshot.

Maps use the application’s caches directory.

The runtime’s system libraries link when Xcode links your app, not when Gradle builds the framework. Add them to your iOS app target’s Other Linker Flags:

-l"c++"
-lz
-framework CoreFoundation
-framework CoreGraphics
-framework CoreText
-framework Foundation
-framework ImageIO
-framework Metal
-framework QuartzCore

Compile the JS target to ES modules. MapLibre Compose declares MapLibre GL JS as an ES module, which a UMD build cannot load.

build.gradle.kts
kotlin {
js {
useEsModules()
browser()
}
}

Configure MapLibre inside onWasmReady, before Compose starts.

main.kt
fun main() {
onWasmReady {
MapLibre.configure()
ComposeViewport(document.body!!) { App() }
}
}

Alongside the library, add a runtime: the native libraries for one platform and one render backend. The runtime artifact you package is what picks the backend the map renders with.

build.gradle.kts
sourceSets {
val jvmMain by getting {
dependencies {
implementation(compose.desktop.currentOs)
implementation("org.maplibre.compose:maplibre-compose:0.14.0")
// Linux x64 with Vulkan, for example.
runtimeOnly(
"org.maplibre.compose:maplibre-compose-runtime-vulkan-linux-x64:" +
"0.14.0"
)
}
}
}

Provide each AWT window’s GPU context:

Main.kt
fun main() {
singleWindowApplication {
ProvideMapHost(host = rememberAwtComposeMapHost(window)) {
App()
}
}
}

Available runtimes:

PlatformRuntime
Linux x64maplibre-compose-runtime-vulkan-linux-x64
Linux arm64maplibre-compose-runtime-vulkan-linux-arm64
macOS arm64maplibre-compose-runtime-metal-macos-arm64
Windows x64maplibre-compose-runtime-vulkan-windows-x64
Windows arm64maplibre-compose-runtime-vulkan-windows-arm64

To ship several platforms, select the runtime from the host you build on. Match the runtime’s version to the library version you selected above, including when that is a snapshot.

Desktop requires Java 25. The MapLibre Native FFI binding uses the FFM API, so the desktop target cannot run on an older JVM.

The JVM needs native access. MapLibre Native FFI makes FFM downcall. If you package your application with Compose Desktop’s nativeDistributions, add the argument to your application configuration:

build.gradle.kts
compose.desktop {
application {
jvmArgs += "--enable-native-access=ALL-UNNAMED"
}
}

If you launch an unpackaged JVM application instead — java -jar, an IDE run configuration, or a JavaExec task — pass the same argument on the command line:

Terminal window
java --enable-native-access=ALL-UNNAMED -jar your-app.jar

In your Composable UI, add a map:

App.kt
@Composable
fun MyApp() {
MaplibreMap()
}

When you run your app, you should see the default demotiles map. To learn how to get a detailed map with all the features you’d expect, proceed to Styling.