# MapLibre Native: vector map rendering you can ship in your own app

> A C++ rendering engine for vector tiles, forked from Mapbox GL Native when the licence changed, now shipped through five different platform bindings with version lines that do not match.

**maplibre/maplibre-native** — MapLibre Native - Interactive vector tile maps for iOS, Android and other platforms.

- Repository: https://github.com/maplibre/maplibre-native
- Website: https://maplibre.org
- Stars: 2,253 · Forks: 638
- Language: C++
- License: BSD-2-Clause
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/maplibre-maplibre-native

## A fork with a reason and a document explaining it

The README states the origin plainly: this project originated as a fork of Mapbox GL Native before Mapbox switched to a non-OSS licence in December 2020, and points to `FORK.md` for the full account. That is the correct way to handle this situation, and it does something important for a reader: it tells you exactly what you are getting and why.

A fork is a liability if you do not know what changed. `FORK.md` existing at the root is the difference between a fork you must audit line by line and a fork with a documented divergence history. For a project embedded in shipping mobile applications, that documentation is the difference between a dependency you can evaluate and one you cannot.

The licensing is BSD-2-Clause, confirmed in both the GitHub metadata and the root `package.json`, and there is a `LICENSE.md` plus a `LICENSES.core.md` at the top level. The second file is worth knowing about, because it suggests the core engine carries its own separate licensing treatment for third party code, which is normal for something vendoring a graphics stack.

The project is not archived, the last push was on 2026-09-28, and there is a `SECURITY.md`, a `CODE_OF_CONDUCT.md` and a `CONTRIBUTING.md`. Open issues sit at 619, which is a large number and mostly reflects the size of the user base rather than neglect.

## Adding a map view on Android

Android integration is a Gradle dependency, a view in a layout file, and an activity. The README gives the coordinate as `org.maplibre.gl:android-sdk:11.11.0`:

```gradle
    dependencies {
        ...
        implementation 'org.maplibre.gl:android-sdk:11.11.0'
        ...
    }
```

The view itself is declared in XML:

```xml
<org.maplibre.android.maps.MapView
    android:id="@+id/mapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
```

Then the activity initialises it and loads a style:

```kotlin
MapLibre.getInstance(this)
...
mapView = rootView.findViewById(R.id.mapView)
mapView.getMapAsync { map ->
    map.setStyle("https://demotiles.maplibre.org/style.json")
    map.cameraPosition = CameraPosition.Builder().target(LatLng(0.0,0.0)).zoom(1.0).build()
}
```

Two details are worth pausing on. First, the style URL points at maplibre.org's own demo tiles, so you can copy this verbatim and see a rendered map before you have any tile infrastructure at all. Second, the activity also forwards the entire `Activity` lifecycle to the map view: `onStart`, `onResume`, `onPause`, `onStop`, `onLowMemory`, `onDestroy` and `onSaveInstanceState` each have a matching `mapView` call. Skipping those is the most common cause of a map that renders once and then breaks on rotation.

For Compose projects the README points to external projects rather than providing first-party support, naming Ramani Maps and MapLibre Compose Playground.

## iOS uses UIKit, and SwiftUI needs a wrapper you write yourself

The iOS story starts with an honest statement: MapLibre Native iOS uses UIKit. You get it from CocoaPods, from the Swift Package Index, or by adding it to Xcode directly. The UIKit integration is short:

```swift
class SimpleMap: UIViewController, MLNMapViewDelegate {
    var mapView: MLNMapView!

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView = MLNMapView(frame: view.bounds)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(mapView)
        mapView.delegate = self
    }
}
```

Note the `MLN` prefix rather than `MapLibre`. That is Mapbox-era naming preserved in the fork, and it is a detail that trips up anyone searching the API surface for the current product name.

For SwiftUI the README is explicit that you need to create a wrapper, and shows the whole thing:

```swift
import MapLibre

struct SimpleMap: UIViewRepresentable {
    func makeUIView(context _: Context) -> MLNMapView {
        let mapView = MLNMapView()
        return mapView
    }

    func updateUIView(_: MLNMapView, context _: Context) {}
}
```

An empty `updateUIView` is a functional starting point but means the wrapper does not propagate state changes, so a reactive SwiftUI data flow will not drive the map. That is your code to write.

A better option exists and the README names it: MapLibreSwiftUI is a separate wrapper project offering a declarative API like SwiftUI. For a SwiftUI-first application, using that is less work than maintaining your own `UIViewRepresentable`.

## Five platform bindings and four version numbers

Beyond mobile there are three more routes. Node.js has an npm package, `@maplibre/maplibre-gl-native`, and the README helpfully notes that the source lives in this same repository under `platform/node`. Qt lives in a separate repository, `maplibre/maplibre-native-qt`. Compose Multiplatform is handled by MapLibre Compose, which as of August 2025 supports iOS and Android with web and desktop partially supported.

And then there is the platform directory for Linux, Windows and macOS, each with its own README. Those are the routes with no ready-made binding, and they are where a C++ toolchain of your own becomes necessary.

Now the version numbers, which do not line up and are worth understanding before you pin anything. The most recent releases are `android-v13.5.2` published 2026-09-23, `ios-v6.31.0` from 2026-09-11 and `ios-v6.30.0` from 2026-09-10. So Android and iOS have independent major version lines that increment at completely different rates.

Against that, the README's Gradle snippet pins `android-sdk:11.11.0` while the newest Android tag is 13.5.2, and the root `package.json` declares version 5.4.0. Three different numbers for three different things, none of which is wrong, and all three are easy to mistake for each other. The rule that follows: choose your version from the platform's own tag line, not from the README snippet and not from the package manifest.

The iOS release cadence is visible in those three tags alone, with 6.30.0 and 6.31.0 a day apart. That is a project shipping frequently.

## A C++ core with a real contribution path

The contributing note states the division of labour directly: MapLibre Native has at its core a C++ library, and that is where the bulk of development is currently happening. Everything else in the repository is a binding on top of it.

The repository tree reflects a large native project rather than a wrapper library. There are `include/` for public headers, `src/` for implementation, `shaders/` for the GPU programs, `vendor/` for third party code, and `platform/` for the per-platform bindings. Build configuration appears three times over: `CMakeLists.txt` with `CMakePresets.json`, `BUILD.bazel` with `MODULE.bazel` and a `.bazelversion`, and `cmake/` for the CMake side.

Three test directories tell you how the project verifies itself. `render-test/` is image comparison for rendering output. `expression-test/` tests the style expression evaluator separately, which is sensible because expressions are the most common source of map styling bugs. `test/` is the general suite, and `benchmark/` exists for performance work.

The root `package.json` is a development manifest rather than a shipping one: it carries an empty description, empty keywords and empty files, and its dependencies are tooling, including the MapLibre GL style spec package, `simple-git`, `npm-run-all` and `minimatch`. There is a `copy-style-spec` script that copies the style spec's latest JSON into `scripts/style-spec-reference/v8.json`, which is how the style reference stays pinned to a specific version.

For anyone reading the code rather than just integrating it, `ARCHITECTURE.md` and the `design-proposals/` directory are the places to start.

## Rendering is fast because it is on the GPU, and that is the whole pitch

The README's one-sentence description is that MapLibre Native is a free and open source library for publishing maps in your apps and desktop applications on various platforms, and that fast display of maps is possible thanks to GPU-accelerated vector tile rendering.

That last clause is the technical substance. A vector tile is a compact binary description of geometry and styling instructions, and rendering it means parsing those instructions and issuing GPU draw calls every frame. Doing that on the CPU is what makes naive map rendering stutter during a pan. The engine therefore carries its own tile pipeline, its own style evaluator, its own text rendering, and shader programs for the different layer types.

The engineering cost of that approach is why the project is large, and why the test infrastructure is image-based. Rendering correctness is a visual property, so testing it means comparing output pixels against known-good references, which is what `render-test/` exists for.

The topics are narrow and accurate: maplibre, maps, vector-tiles. There is no topic for tile serving, because that is not what this repository does. You supply a style and a tile source; the library handles the client side. That boundary is worth being clear about when evaluating, since a great many people searching for a mapping library actually need tile generation or hosting, and no amount of reading this README will change that.

## Conclusion

MapLibre Native is the piece of infrastructure most teams only discover when Mapbox asks for a licence key. What is genuinely hard about it is the packaging rather than the rendering: five platform bindings, two independently versioned release lines, and a C++ core you only compile if you are building a platform nobody has wrapped yet. For an existing app the fastest path is the Android Maven coordinate or the iOS CocoaPods package, and the sample style URL in the README is enough to confirm rendering works before you design anything. Start there, and if you need desktop Linux, Windows or macOS, read the platform-specific READMEs rather than assuming the mobile bindings cover them.

## FAQ

### What are the key differences between MapLibre and Mapbox?

MapLibre Native is a fork of what was Mapbox GL Native, created before Mapbox changed to a non-OSS licence in December 2020. It is BSD-2-Clause licensed and governed by the MapLibre organisation, and the README points to a FORK.md file documenting exactly how the two have diverged.

### Is MapLibre free?

Yes. The license is BSD-2-Clause, stated in both the repository metadata and the package manifest, with a LICENSE.md at the root. You do not need an API key to use the library itself, though you will still need a source of vector tiles and a style, which is a separate question.

### How do I add MapLibre Native to an Android app?

Add the org.maplibre.gl:android-sdk Gradle dependency, put an org.maplibre.android.maps.MapView in your layout XML, and initialise it in your activity. Call MapLibre.getInstance, then use getMapAsync and setStyle to load a style URL. Forwarding the activity lifecycle to the map view is required.

### Does MapLibre Native work with SwiftUI?

Not directly, because the iOS library is built on UIKit. The README shows a UIViewRepresentable wrapper you write yourself, though its updateUIView is empty. For a declarative API, MapLibreSwiftUI is a separate wrapper project the README recommends as an alternative.

### Can I use MapLibre with Python?

There is no Python binding listed in this repository. The documented routes are Android, iOS, Node.js, Qt and Compose Multiplatform, plus the C++ core for platforms you build yourself. The Node package runs the same native engine in a JS process, which is the closest available equivalent.

### Which version of MapLibre Native should I pin?

Pin from the release tag for your platform, not from the README snippet. Android and iOS have independent major version lines, with recent tags such as android-v13.5.2 and ios-v6.31.0, while the README's Gradle example and the package.json manifest show different numbers again.

## Sources

- [License: BSD-2-Clause](https://github.com/maplibre/maplibre-native/blob/main/LICENSE)
- [maplibre/maplibre-native on GitHub](https://github.com/maplibre/maplibre-native)
- [Project website](https://maplibre.org)
- [README](https://github.com/maplibre/maplibre-native/blob/main/README.md)
- [Releases](https://github.com/maplibre/maplibre-native/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/maplibre-maplibre-native
