Get started
Pick your platform, get a map on screen
The SDK we recommend for each platform, how to install it, and a snippet that shows a map with a free basemap. No API key needed.
Web
JavaScript
Used by 103 products in the showcase
npm install maplibre-glimport {Map, setWorkerUrl} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
// MapLibre GL JS v6 + a bundler: set the worker URL once (Vite shown)
setWorkerUrl(workerUrl);
const map = new Map({
container: 'map', // <div id="map" style="height: 400px"></div>
style: 'https://tiles.openfreemap.org/styles/liberty',
center: [0, 20], // [lng, lat]
zoom: 2
});›No bundler (CDN, ES module)
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@^6.11.2/dist/maplibre-gl.css" />
<div id="map" style="height: 400px"></div>
<script type="module">
import * as maplibregl from 'https://unpkg.com/maplibre-gl@^6.11.2/dist/maplibre-gl.mjs';
const map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.openfreemap.org/styles/liberty',
center: [0, 20],
zoom: 2
});
</script>›Setup noteschecked with v6.11.2
Current release is maplibre-gl 6.11.2 (v6), not v5. v6 ships as ES modules only: use named imports (import {Map} from 'maplibre-gl') or a namespace import. The default import (import maplibregl from 'maplibre-gl') no longer works. With a bundler you must call setWorkerUrl() once before the first map is created. Without it the worker fails to load and no tiles render. The snippet shows the Vite setup from the official docs. Use ?worker&url, not ?url, because ?url leaves out the worker's sibling file maplibre-gl-shared.mjs in production builds. For webpack 5+ use setWorkerUrl(new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url).toString()). For Next.js (Turbopack or webpack), esbuild and Rollup, copy maplibre-gl-worker.mjs and maplibre-gl-shared.mjs into your served output and point setWorkerUrl at the worker (see the Installation section of the docs). Loading from a CDN with <script type="module"> needs no setWorkerUrl (see the alternative snippet); pin the major version (e.g. @^6.11.2), because the v5 to v6 migration guide warns that a page pinned to @latest shows a blank gray map with a 404. Import the CSS: markers, popups and controls need it. The map container must have a height. v6 requires WebGL2.
Web
React
React Map GLReact wrapper for MapLibre GL JSUsed by 2 products in the showcase
Also for React: maplibre-react-components
npm install react-map-gl maplibre-glimport Map from 'react-map-gl/maplibre';
import {setWorkerUrl} from 'maplibre-gl';
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
import 'maplibre-gl/dist/maplibre-gl.css';
// MapLibre GL JS v6 + a bundler: set the worker URL once (Vite shown)
setWorkerUrl(workerUrl);
export default function App() {
return (
<Map
initialViewState={{longitude: 0, latitude: 20, zoom: 2}}
style={{width: '100%', height: 400}}
mapStyle="https://tiles.openfreemap.org/styles/liberty"
/>
);
}›Setup noteschecked with v8.1.3
Use react-map-gl 8.1.3 with the react-map-gl/maplibre entry point. This is the path documented in the react-map-gl README, its Get Started guide and its examples. @vis.gl/react-maplibre (also 8.1.3) is the same code: react-map-gl/maplibre re-exports it (export * from '@vis.gl/react-maplibre'), and react-map-gl lists it as a dependency. Its standalone repo (visgl/react-maplibre) is archived with a notice that the code moved into react-map-gl, and it has no maintained docs. It still works if you want a smaller dependency tree (import {Map} from '@vis.gl/react-maplibre'), but it is not the documented path. react-map-gl 8.1 supports MapLibre v4, v5 and v6. With v6 and a bundler you must set the worker URL. The snippet uses Vite's ?worker&url import, like react-map-gl's official maplibre example; for other bundlers see MapLibre's Installation docs. Import the CSS. In Next.js, render the map in a 'use client' component and follow MapLibre's Turbopack worker setup instead of the ?worker&url import.
Web
Vue
@indoorequal/vue-maplibre-glVue 3 plugin for MapLibre GL JSAlso for Vue: Vue MapLibre, LibreGL
npm install @indoorequal/vue-maplibre-gl maplibre-gl<script setup>
import { MglMap } from '@indoorequal/vue-maplibre-gl';
import { setWorkerUrl } from 'maplibre-gl';
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
import 'maplibre-gl/dist/maplibre-gl.css';
// MapLibre GL JS v6 + a bundler: set the worker URL once (Vite shown)
setWorkerUrl(workerUrl);
</script>
<template>
<mgl-map
map-style="https://tiles.openfreemap.org/styles/liberty"
:center="[0, 20]"
:zoom="2"
height="400px"
/>
</template>›Setup noteschecked with v9.0.1
@indoorequal/vue-maplibre-gl 9.0.1 (v9.0.0 made maplibre-gl ^6 a requirement) for Vue 3. The library does not set the MapLibre v6 worker for you. With a bundler you must call setWorkerUrl once before the first map is created, or no tiles render. The snippet uses the same Vite ?worker&url setup the library's own docs site uses (docs/examples/example.data.js). The library's getting-started page does not show this step yet, and its installation page still lists maplibre-gl 5.x. You can move setWorkerUrl and the CSS import to main.ts. Import the CSS. MglMap's width and height default to 100%, so either give the parent a height or pass the height prop. To register every component globally, use app.use(VueMaplibreGl) with the default export. Nuxt has a separate guide (guide/nuxt).
Web
Svelte
Svelte MapLibre GL (MIERUNE)Svelte 5 wrapper for MapLibre GL JSUsed by 1 product in the showcase
Also for Svelte: Svelte MapLibre
npm install -D svelte-maplibre-gl maplibre-gl<script lang="ts">
import 'svelte-maplibre-gl/vite'; // Required only for GL JS v6+
import { MapLibre } from 'svelte-maplibre-gl';
</script>
<!-- The map needs a height, otherwise its size is zero -->
<MapLibre
inlineStyle="height: 400px;"
style="https://tiles.openfreemap.org/styles/liberty"
center={[0, 20]}
zoom={2}
/>›Setup noteschecked with v2.2.1
svelte-maplibre-gl 2.2.1, Svelte 5 only (peer svelte >=5), peer maplibre-gl ^5.19.0 or ^6.0.0. The official quickstart installs only svelte-maplibre-gl, since npm and pnpm install the maplibre-gl peer automatically. Listing maplibre-gl explicitly is harmless. With maplibre-gl v6, import 'svelte-maplibre-gl/vite' once: it calls setWorkerUrl with Vite's ?worker&url import, only in the browser, so it is safe under SvelteKit SSR. On the MapLibre component, the style prop is the map style URL. Use class or inlineStyle for CSS (the official examples use the Tailwind class h-[400px]). maplibre-gl.css is loaded automatically from unpkg. Set autoloadGlobalCss={false} if you want to import it yourself.
Web
Angular
Ngx MapLibre GLOfficialAngular wrapper for MapLibre GL JSUsed by 2 products in the showcase
npm install @maplibre/ngx-maplibre-gl maplibre-gl// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideMaplibreWorker } from '@maplibre/ngx-maplibre-gl/config';
export const appConfig: ApplicationConfig = {
providers: [provideMaplibreWorker('maplibre-gl-worker.mjs')],
};
// app.component.ts
import { Component } from '@angular/core';
import { MapComponent } from '@maplibre/ngx-maplibre-gl';
@Component({
selector: 'app-root',
imports: [MapComponent],
template: `
<mgl-map
[mapStyle]="'https://tiles.openfreemap.org/styles/liberty'"
[center]="[0, 20]"
[zoom]="2"
/>
`,
styles: [`mgl-map { height: 400px; }`],
})
export class AppComponent {}›Setup noteschecked with v22.1.0
@maplibre/ngx-maplibre-gl 22.1.0 needs Angular 22+ (@angular/core >=22) and maplibre-gl >=6. MapComponent is standalone. Import NgxMapLibreGLModule instead if you use many components. In this version [zoom], [pitch], [bearing] and [roll] take plain numbers; older versions used [zoom]="[9]". Two setup steps are required for MapLibre v6, or the worker 404s and no tiles render. (1) In angular.json, under the build target's assets, add two entries with input "node_modules/maplibre-gl/dist" and output "/": one with glob "maplibre-gl-worker.mjs" and one with glob "maplibre-gl-shared.mjs". (2) Add provideMaplibreWorker('maplibre-gl-worker.mjs') to your application providers, next to the ones you already have. Load the CSS: add "./node_modules/maplibre-gl/dist/maplibre-gl.css" to angular.json styles, or put @import 'maplibre-gl/dist/maplibre-gl.css'; in styles.css. The README says you may also need "skipLibCheck": true (and "strictNullChecks": false) in tsconfig.json.
Mobile
iOS
Used by 53 products in the showcase
Also for iOS: MapLibre SwiftUI DSL
Swift Package Manager: https://github.com/maplibre/maplibre-gl-native-distribution (product "MapLibre", version 6.31.0, Up to Next Major)import MapLibre
import SwiftUI
struct SimpleMap: UIViewRepresentable {
func makeUIView(context _: Context) -> MLNMapView {
let mapView = MLNMapView(
frame: .zero,
styleURL: URL(string: "https://tiles.openfreemap.org/styles/liberty")
)
mapView.setCenter(CLLocationCoordinate2D(latitude: 20, longitude: 0), zoomLevel: 2, animated: false)
return mapView
}
func updateUIView(_: MLNMapView, context _: Context) {}
}
struct ContentView: View {
var body: some View {
SimpleMap().ignoresSafeArea()
}
}›Setup noteschecked with v6.31.0
The latest release is 6.31.0 (2026-09-11). In Xcode, choose File > Add Package Dependencies, paste the URL and add the MapLibre library product. The official Getting Started guide covers SwiftUI (a UIViewRepresentable around MLNMapView) and UIKit (a UIViewController). The MLNMapView(frame:styleURL:) and setCenter(_:zoomLevel:animated:) calls follow the official Swift examples, and those examples use this exact OpenFreeMap Liberty URL (ExampleStyles.md). Without a styleURL, the map shows the MapLibre demotiles style. The package is also on CocoaPods (pod 'MapLibre'), where the newest version is currently 6.30.0. The podspec sets the iOS deployment target to 15.5.
Mobile
Android
MapLibre Native Android SDKOfficialOfficial MapLibre Native SDK for AndroidUsed by 64 products in the showcase
Also for Android: Ramani Maps
implementation("org.maplibre.gl:android-sdk:13.6.1")import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.maplibre.android.MapLibre
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView
class MainActivity : AppCompatActivity() {
private lateinit var mapView: MapView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapLibre.getInstance(this) // before creating the MapView
mapView = MapView(this)
setContentView(mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
map.setStyle("https://tiles.openfreemap.org/styles/liberty")
map.cameraPosition = CameraPosition.Builder()
.target(LatLng(20.0, 0.0))
.zoom(2.0)
.build()
}
}
// MapView must receive the activity's lifecycle callbacks
override fun onStart() { super.onStart(); mapView.onStart() }
override fun onResume() { super.onResume(); mapView.onResume() }
override fun onPause() { super.onPause(); mapView.onPause() }
override fun onStop() { super.onStop(); mapView.onStop() }
override fun onLowMemory() { super.onLowMemory(); mapView.onLowMemory() }
override fun onDestroy() { super.onDestroy(); mapView.onDestroy() }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}›Setup noteschecked with v13.6.1
The latest stable release is 13.6.1 (Maven Central). Ignore 13.6.1-pre0: it is a pre-release, even though maven-metadata lists it as newest. The official quickstart's example version (11.8.0) is out of date. Groovy DSL: implementation 'org.maplibre.gl:android-sdk:13.6.1'. The repository is mavenCentral(). Since 13.0.0, android-sdk renders with Vulkan. For OpenGL ES, use org.maplibre.gl:android-sdk-opengl (same version). Call MapLibre.getInstance(context) before the MapView is created or inflated. The official quickstart inflates a <org.maplibre.android.maps.MapView> from XML. This snippet creates the MapView in code with the public MapView(Context) constructor, so no layout file is needed. MapView's javadoc says onCreate(savedInstanceState) and every lifecycle method must be forwarded (the official test app does this; the quickstart skips onCreate). LatLng takes latitude first.
Cross-platform
React Native
MapLibre React NativeOfficialReact Native wrapper for MapLibre NativeUsed by 2 products in the showcase
npm install @maplibre/maplibre-react-nativeimport { Camera, Map } from "@maplibre/maplibre-react-native";
export default function App() {
return (
<Map mapStyle="https://tiles.openfreemap.org/styles/liberty">
<Camera initialViewState={{ center: [0, 20], zoom: 2 }} />
</Map>
);
}›Setup noteschecked with v11.4.0
@maplibre/maplibre-react-native 11.4.0 (v11). v11 renamed MapView to Map (mapStyle prop), renamed Camera defaultSettings to initialViewState ({center: [lng, lat], zoom}), and supports only the New Architecture. It requires React Native >=0.80, React >=19.1 and Android API 23+. It wraps MapLibre Native Android 13.6.1 and iOS 6.31.0. Map fills its parent by default (style defaults to {flex: 1}). Expo: run npx expo install @maplibre/maplibre-react-native, add "@maplibre/maplibre-react-native" to expo.plugins in app.json, then rebuild (Expo >=54, a development build; Expo Go is not supported). Bare React Native: add $MLRN.post_install(installer) to the post_install block of ios/Podfile, run pod install in ios/, then rebuild. Android needs no extra setup.
Cross-platform
Flutter
Flutter MapLibre GL (Official)OfficialOfficial Flutter plugin for MapLibreUsed by 2 products in the showcase
Also for Flutter: Flutter MapLibre
flutter pub add maplibre_glimport 'package:flutter/material.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
class MapPage extends StatelessWidget {
const MapPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: MapLibreMap(
styleString: 'https://tiles.openfreemap.org/styles/liberty',
initialCameraPosition: const CameraPosition(
target: LatLng(20.0, 0.0), // latitude, longitude
zoom: 2,
),
),
);
}
}›Setup noteschecked with v0.27.1
maplibre_gl 0.27.1 on pub.dev. The pubspec line is maplibre_gl: ^0.27.1. It requires Flutter 3.29+ and Dart 3.7+, JDK 21 for Android builds, Android 5.0 (API 21)+, iOS 13+, and a WebGL2 browser for web. Platforms: Android, iOS and Web (no desktop). LatLng takes latitude first. The map needs bounded constraints (for example a Scaffold body). Location permissions are only needed if you show the user's location. On web, since 0.27.0 the plugin loads MapLibre GL JS 6 itself: add nothing to web/index.html, and remove old maplibre-gl.js/.css tags if your index.html has them. Add sources and layers in onStyleLoadedCallback.
Cross-platform
Compose Multiplatform
MapLibre ComposeOfficialCompose Multiplatform wrapper for MapLibreUsed by 2 products in the showcase
// build.gradle.kts (Kotlin Multiplatform)
commonMain.dependencies {
implementation("org.maplibre.compose:maplibre-compose:0.18.0")
}
androidMain {
dependencies {
runtimeOnly("org.maplibre.compose:maplibre-compose-runtime-vulkan-android:0.18.0")
}
}import androidx.compose.runtime.Composable
import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.map.MaplibreMap
import org.maplibre.compose.map.rememberMapState
import org.maplibre.compose.style.BaseStyle
import org.maplibre.spatialk.geojson.Position
@Composable
fun App() {
val mapState = rememberMapState(
baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"),
initialCameraPosition = CameraPosition(
target = Position(latitude = 20.0, longitude = 0.0),
zoom = 2.0,
),
)
MaplibreMap(state = mapState)
}›Setup noteschecked with v0.18.0
maplibre-compose 0.18.0 (2026-09-25) on Maven Central. It is pre-1.0, and minor releases can contain breaking changes. Android and iOS are Beta, desktop and web are Alpha. The API changed in 0.16.0: the style and initial camera now go into rememberMapState(baseStyle = BaseStyle.Uri(...), initialCameraPosition = ...), which you pass as MaplibreMap(state = ...). Tutorials that pass baseStyle and cameraState = rememberCameraState(...) directly to MaplibreMap were written for 0.15 and earlier. Android also needs one render runtime at the same version: maplibre-compose-runtime-vulkan-android or maplibre-compose-runtime-opengl-android. iOS needs iOS 15.5+ and these Other Linker Flags: -l"c++" -lz -framework CoreFoundation -framework CoreGraphics -framework CoreText -framework Foundation -framework ImageIO -framework Metal -framework QuartzCore. Desktop (JVM) needs Java 25+, a per-platform runtime artifact and --enable-native-access=ALL-UNNAMED. Web needs useEsModules() and installMapLibreCompose() inside onWasmReady. Position is the GeoJSON type, so use the named latitude and longitude arguments (the positional order is longitude, latitude).
Next steps
Pick a different look on the basemaps page, then add what your map needs.