Skip to content

Install

Choose a render backend first. Prefer Metal for Apple platforms, OpenGL for emulators and virtual machines, and Vulkan for other platforms. Then install the C library, a binding for your language, or both. Each section covers its tagged releases, where they exist, and its snapshot channel.

Download maplibre-native-c-<preset>.tar.gz for the target from the latest release and unpack it. The archive root is the install prefix. The snapshot release carries the same assets built from main under a fixed tag, so its download URLs stay stable.

A preset name has the form <platform>-<arch>-<backend>, as in macos-arm64-metal or linux-x64-vulkan. OpenGL presets name their context provider in place of the backend: egl, wgl, or webgl. Platforms gives the provider for each platform.

On Windows, add <prefix>/bin to PATH or copy maplibre-native-c.dll beside your executable, because a prefix carries no loader path there. Linux and macOS builds record an rpath into the prefix that they built against.

Export PKG_CONFIG_PATH to build against the prefix:

Terminal window
export PKG_CONFIG_PATH=<prefix>/share/pkgconfig
cc -std=c23 main.c $(pkg-config --cflags --libs maplibre-native-c) -o main

To build a prefix yourself, see the development overview.

Each binding wraps the C library in one language. Most carry or download the C library, and the sections that need an installed prefix say so.

Add Maven Central, the binding, and the runtime for your backend. The runtime carries the native library for every ABI.

build.gradle.kts
repositories {
mavenCentral()
}
dependencies {
implementation("org.maplibre.nativeffi:maplibre-native-ffi:0.202608.0")
implementation("org.maplibre.nativeffi:maplibre-native-ffi-runtime-vulkan:0.202608.0")
}

Take one runtime module:

  • org.maplibre.nativeffi:maplibre-native-ffi-runtime-opengl
  • org.maplibre.nativeffi:maplibre-native-ffi-runtime-metal
  • org.maplibre.nativeffi:maplibre-native-ffi-runtime-vulkan

On Android, initialize platform services before you create a runtime, as Android describes.

For the snapshot channel, add the Maven snapshot repository and take the snapshot version of both modules. The runtime modules and Android initialization match the release.

build.gradle.kts
repositories {
maven("https://central.sonatype.com/repository/maven-snapshots/") {
content { includeGroup("org.maplibre.nativeffi") }
}
mavenCentral()
}
dependencies {
implementation("org.maplibre.nativeffi:maplibre-native-ffi:0.1.0-SNAPSHOT")
implementation("org.maplibre.nativeffi:maplibre-native-ffi-runtime-vulkan:0.1.0-SNAPSHOT")
}

Add the snapshot feed, then the binding and the runtime for your backend.

nuget.config
<configuration>
<packageSources>
<add key="maplibre-snapshots" value="https://maplibre.github.io/maplibre-native-ffi/nuget/index.json" />
</packageSources>
</configuration>
MyApp.csproj
<ItemGroup>
<PackageReference Include="Maplibre.NativeFfi" />
<PackageReference Include="Maplibre.NativeFfi.Runtime.Vulkan" />
</ItemGroup>

Take one runtime package:

  • Maplibre.NativeFfi.Runtime.OpenGL
  • Maplibre.NativeFfi.Runtime.Metal
  • Maplibre.NativeFfi.Runtime.Vulkan

Depend on the package from Git. The build hook downloads a native artifact for your target when you build.

pubspec.yaml
dependencies:
maplibre_native_ffi:
git:
url: https://github.com/maplibre/maplibre-native-ffi
path: bindings/dart

The hook chooses the default backend from the target. Name a different one in your application’s pubspec to override that.

pubspec.yaml
hooks:
user_defines:
maplibre_native_ffi:
backend: vulkan

The backends are opengl, metal, and vulkan.

Write an install prefix into .dart_tool/maplibre_native_install_dir to use your own build instead. A pinned Git revision keeps the Dart code fixed, and the hook still resolves the current snapshot for a build that has no artifact cached. Point the hook at your own prefix when you need a fixed native library.

Terminal window
go get github.com/maplibre/maplibre-native-ffi/bindings/go@main

Install the C library, then export PKG_CONFIG_PATH before you build. cgo reads it.

Depend on the distribution for your backend and resolve it from the snapshot index. The wheels contain the native library.

pyproject.toml
[project]
dependencies = ["maplibre-native-ffi-vulkan"]
[[tool.uv.index]]
name = "maplibre-snapshots"
url = "https://maplibre.github.io/maplibre-native-ffi/simple/"
explicit = true
[tool.uv.sources]
maplibre-native-ffi-vulkan = { index = "maplibre-snapshots" }

This index configuration uses uv. The explicit index limits snapshot resolution to this package; all other dependencies continue to resolve from PyPI.

Take one distribution:

  • maplibre-native-ffi-opengl
  • maplibre-native-ffi-metal
  • maplibre-native-ffi-vulkan

Depend on the maplibre-native-ffi crate from Git and enable one backend feature. The build script downloads the matching native artifact.

Cargo.toml
[dependencies]
maplibre-native-ffi = { git = "https://github.com/maplibre/maplibre-native-ffi", features = ["vulkan"] }

Enable one backend feature: opengl, metal, vulkan, or webgpu.

Set MAPLIBRE_NATIVE_C_INSTALL_DIR to an install prefix to use your own build instead.

The package manifest at the repository root defines the Swift package.

Package.swift
.package(url: "https://github.com/maplibre/maplibre-native-ffi", branch: "main")

Depend on the MaplibreNativeFFI product. SwiftPM takes the package identity from the repository name rather than from the manifest, so name it as maplibre-native-ffi.

Package.swift
.product(name: "MaplibreNativeFFI", package: "maplibre-native-ffi")

Install the C library, then export PKG_CONFIG_PATH before you build.

Terminal window
zig fetch --save git+https://github.com/maplibre/maplibre-native-ffi

Install the C library, then pass -Dnative-install-dir=<prefix> when you build.

Linux runs the Vulkan and OpenGL backends, with EGL as the OpenGL context provider.

macOS runs the Metal, Vulkan, and OpenGL backends, with EGL as the OpenGL context provider. Apple provides neither Vulkan nor EGL, so a host that chooses one of those backends loads MoltenVK or ANGLE itself.

Windows runs the Vulkan and OpenGL backends, with WGL as the OpenGL context provider.

Android runs the Vulkan and OpenGL backends, with EGL as the OpenGL context provider.

An Android app using Kotlin/JVM depends on a Kotlin runtime AAR. The AAR carries the native library for every ABI and the platform TLS component that Android HTTPS requests require.

build.gradle.kts
implementation("org.maplibre.nativeffi:maplibre-native-ffi-runtime-vulkan:0.202608.0")

A Kotlin/Native target gets the native library from its runtime KLIB. Add the matching runtime AAR directly to the module that packages the APK or AAB so that the app also carries the TLS component. Exclude the AAR’s shared library because the Kotlin/Native host library already contains the static runtime.

build.gradle.kts
dependencies {
implementation("org.maplibre.nativeffi:maplibre-native-ffi-runtime-vulkan-android:0.202608.0")
}
android {
packaging {
jniLibs.excludes += "**/libmaplibre-native-c.so"
}
}

Initialize the platform once before you create a runtime, passing an android.content.Context. Every binding exposes this call under its own name. Android HTTPS requests validate against the app’s trust policy from that point on. Kotlin/JVM hosts call MaplibreAndroid.initialize(context). Kotlin/Native hosts create AndroidJniEnvironment and AndroidContextReference values from host JNI addresses, then pass them to MaplibreAndroid.initialize.

iOS runs the Metal backend, on the device and in the simulator.

OpenHarmony runs the Vulkan and OpenGL backends, with EGL as the OpenGL context provider.

Emscripten runs the WebGPU and OpenGL backends, with WebGL as the OpenGL context provider.