v5 to v6 migration guide
MapLibre GL JS v6 ships as ES modules only. The UMD bundle and the separate CSP build from v5 are gone. The bundle file is now maplibre-gl.mjs (and maplibre-gl-worker.mjs).
Imports
If you import maplibre-gl from npm with named imports (import {Map} from 'maplibre-gl'), your imports keep working: v6 resolves to the ESM bundle automatically.
If you used the default import (import maplibregl from 'maplibre-gl'), switch to either named imports or a namespace import:
// before
import maplibregl from 'maplibre-gl';
// after
import * as maplibregl from 'maplibre-gl';
// or pull in just what you need
import {Map, setWorkerUrl} from 'maplibre-gl';
<script> tag
If you load maplibre-gl via <script src>, switch to a module script:
<!-- before -->
<script src="https://unpkg.com/maplibre-gl@^5/dist/maplibre-gl.js"></script>
<!-- after -->
<script type="module">
import * as maplibregl from 'https://unpkg.com/maplibre-gl@^6.0.0/dist/maplibre-gl.mjs';
</script>
setWorkerUrl() is bundler-only
For direct browser ESM (loading from a CDN like unpkg via a <script type="module"> tag), the worker URL is auto-detected from import.meta.url and laundered through a same-origin Blob URL when needed, so no setWorkerUrl() call is required.
For bundlers (Vite, webpack, esbuild, rspack, Rollup), import.meta.url doesn't reliably resolve to the worker file inside the bundler's module graph, so each consumer still needs a one-time setWorkerUrl() call. See Installation for per-bundler snippets.
CSP directives
The dedicated CSP bundle from v5 is no longer needed.
If you load MapLibre from a CDN cross-origin to your page (e.g. unpkg), the worker is constructed from a same-origin Blob URL, so your CSP needs to allow blob: in worker-src:
If you self-host the worker file (any bundler setup), the worker URL is same-origin and blob: is not required:
zoomLevelsToOverscale
In version 5 there was an experimental parameter added to allow slicing vector tiles instead of overscaling them.
We tested it, and it looks like it fixes a lot of issue in labeling etc.
It does changes rendering and the results of queryRenderedFeatures.
If you would like to revert to the previous behavior you can set zoomLevelsToOverscale: undefined when initializing the map.
pragma mapbox
In case you were using #pragma mapbox in your shared code please replace it with #pragma maplibre.
Events
All events are now classes, it is advised not to use instanceof but instead check the type field. Since the change was from types to classes this shouldn't be a problem in most code bases.
styleimagemissing
In v6, styleimagemissing listeners can no longer resolve the current image request by calling Map#addImage. To migrate a listener that supplies missing images, replace it with Map#setMissingStyleImageResolver:
-map.on('styleimagemissing', ({id}) => {
+map.setMissingStyleImageResolver((id) => {
map.addImage(id, generateImage(id));
});
The resolver can be synchronous or asynchronous. For asynchronous loading, call Map#addImage before the resolver's promise settles. The styleimagemissing event can still be used to observe images that remain unresolved.