Immutable
release. Only release title and notes can be modified.
The following incorporates all the pre-releases for version 6 changes.
Check-out our migration guide from v5 to v6 for more information.
✨ Features and improvements
⚠️ Switch to an ESM-only distribution (maplibre-gl.mjs). The UMD bundles (maplibre-gl.js,maplibre-gl-csp.js) are no longer published. The CSP-specific bundle is also dropped: the ESM build loads its worker as a real URL, soworker-src blob:is no longer required. Consumers using<script src=".../maplibre-gl.js">must switch to<script type="module">, and consumers usingimport maplibregl from 'maplibre-gl'must switch toimport * as maplibregl from 'maplibre-gl'or named imports. See the docs ESM section or our migration guide for migration steps. (#6254) (by @birkskyum)⚠️ Interpolate the light position in spherical coordinates instead of cartesian ones, so that a transition keeps its radial distance. (#7919) (by @HarelM)⚠️ styleimagemissingis now a notify-only event instead of the previous callback that allowed to provide an image. This aligns the event with standard event semantics (notify, not resolve). UseMap.setMissingStyleImageResolverto on-demand supply images instead via an function that can now also be async. (#7892) (by @birkskyum)⚠️ Mapnow composes aCamerainstead of extending it (MapextendsEventeddirectly and forwards the camera API). The internalmap.transformwas removed — use map's public API instead or open a PR if you need something that's not exposed. Removed the internaltransform.getMatrixForModelhelper (#7800) (by @HarelM)⚠️ All map events are now real classes that are instantiated when they are fired. Renamed theMaps'BoxZoomhandler fromMapLibreZoomEventtoMapBoxZoomEvent, added therollstart/roll/rollendandstyle.load(asMapStyleLoadEvent) events toMapEventType, and added event classes and type-map forMarker,Popup,GeolocateControlandFullscreenControl. RemovedMapDataEvent: thedata/dataloading/dataabortevents are nowMapSourceDataEvent | MapStyleDataEvent, so source data events carry the full source info (sourceId,tile,sourceDataType, …). AddedMapMovementEventas the type for all camera-transition events (move/zoom/rotate/pitch/roll/dragand theirstart/endvariants).Eventedis now generic over an event-type map (Evented<EventType>) and isabstract, so subclasses get strongly-typedon/once/offautomatically without re-declaring overloads — this also types the events onCamera/Style(viaMapEventType) and on the sources (via the newSourceEventType) (#7789) (by @HarelM)⚠️ Update maplibre-gl-style-spec to version 25, which now throws an error with warning severity instead of silently failing on encoutering legacy expressions (#7792) (by @HarelM)⚠️ Removed the remaining mapbox references in the code and in the tests. This changes the#pragma mapboxto#pragma maplibrein case you have shader code that relied on it. (#7761) (by @HarelM)⚠️ zoomLevelsToOverscaledefault value was changed to 4 to support better handling of high level zoom with dense labels. This might have a side effect of changing a bit the results ofqueryRenderedFeaturesand some rendering of polygon center label. To revert this change, set the value toundefined(#7537) (by @HarelM)⚠️ Remove the second parameter fromGeoJSONSource.setData(waitForCompletion) and remove the return value ofthisto allow future changes to the API (#7538) (by @HarelM)⚠️ The TypeScript target has been updated to ES2022.
This results in smaller bundles and improved runtime performance by relying on modern JavaScript features and reducing transpilation. Consumers targeting browsers or using some tooling released before 2022 may need to transpile MapLibre or update. This change also aligns all internal build configurations to a single target instead of ES2016 + ES2019, avoiding inconsistencies in emitted code. (#7404) (by @CommanderStorm)⚠️ WebGL (v1) support has been removed; WebGL2 is now required.
In practical terms, this will not change how you interact with the map.
This enables performance improvements (e.g. line opacity), Terrain3D enhancements, and several bug fixes.
WebGL2 support has been widely available for years, and usage of the legacy path had plateaued, so maintaining it no longer justified the added complexity.
To ease this breaking change, we have also refactored how we handle the case that no webgl is avaliable (e.g. due to browser restrictions).
You can now listen to the webgl error via.on("error").
See caniuse.com/webgl2 for ecosystem support and our RFC for details. (#7453) (by @CommanderStorm)⚠️ Support geojson nested objects, this is a breaking change as it encodes__$json__before properties that used to be an object. It also parses them back, but this is still a breaking change if you assumed this bug existed. (#6992) (by HarelM)⚠️ Improve types for{get,set}LayoutProperty,{get,set}PaintPropertyto be the actual type instead ofstring/any(#7481) (by @CommanderStorm)⚠️ Refactored theHash-based location control (the option that syncs map state to the URL like#map=5/1/2) to useURLSearchParamsinternally. This improves extensibility for custom use cases, but may break existing code that relies on the previous implementation. It also changes how certain edge cases are parsed—for example, strings like#10%2F3.00%2F-1.00are now accepted, and hashes like#fooare normalized to#foo=. (#7073) (by @CommanderStorm)- Validate the terrain passed to
map.setTerrain, which was previously applied unchecked (#7941) (by @HarelM) - Improve runtime error warnings to point at the offending style location (e.g.
layers[3].paint.line-color,layers[3].filter) instead of just logging the bare error message (#7869) (by @CommanderStorm) - Improve terrain render-to-texture preparation performance by skipping sources that are not rendered to terrain textures (#7863) (by @DoFabien)
- Add
Map.setMissingStyleImageResolverfor resolving missing style images with sync or async callbacks (#7850) (by @birkskyum) - Add
RasterTileSource#setPremultiplyAlpha(false)to preserve raw RGBA tile values when alpha is used for data instead of opacity (#7235) (by @plantain). - Drop the archived
@mapbox/whoots-jsdependency by inlining its singlegetTileBBoxhelper (#7838) (by @qorexdevs) - Debounce
setImagesbroadcast to once per animation frame, fixing O(n²) serialization overhead when adding many images (#7614) (by @bradymadden97) - Improve terrain rendering performance by avoiding unnecessary terrain data lookups during Mercator render-to-texture passes (#7833) (by @DoFabien)
- Reduce allocation pressure while constructing DEM data and sampling terrain elevations (#7814) (by @DoFabien)
- Reuse terrain DEM texture when preparing terrain (#7813) (by @DoFabien)
- Add
fill-layer-opacityandline-layer-opacitypaint properties, which apply opacity to the entire layer output uniformly (#7570) (by @CommanderStorm) - Build main and worker in same build context to extract shared chunk (#7745) (by @dangkyokhoang)
- Revert the
line-opacity-driven offscreen rendering introduced in #7490 (#7764) (by @CommanderStorm). The overlap-artefact fix is now driven byline-layer-opacityinstead. - Improve
ProjectionDatamatrix backing types for renderer and custom layer projection matrices (#6316) (by @cat0825) - Optimization: vertex shader opacity culling for lines and fills #7711 (by @xavierjs)
- Use a shared FBO for the terrain cache render to texture #7637 (by @xavierjs)
- Use
flatto opt out of interpolation for constant shader varyings (#7661) (by @birkskyum) - Replace texImage2D with texStorage2D for immutable textures (#7643) (by @birkskyum)
- Enable mipmaps for non-power-of-two raster tiles, reducing aliasing at high pitch (#7641) (by @birkskyum)
- Use GLSL ES 3.00 layout qualifiers for vertex attribute locations, replacing runtime
bindAttribLocationcalls (#7644) (by @birkskyum) - Adopt isolatedDeclarations and switch dts emitter from tsgo to oxc (#7566) (by @birkskyum)
- Improve 3D terrain performance (#7549) (by @lucaswoj)
- Replace dts-bundle-generator with rolldown-plugin-dts for 78.2x faster .d.ts generation. (#7564) (by @birkskyum)
- Replace ts-node with Node 24's native TypeScript support for build scripts. (#7565) (by @birkskyum)
- Bump typescript to v7 beta - 3.5x faster typecheck (#7556) (by @birkskyum)
- Add a new map creation option,
terrainSkirtLength, which allows the removal of visually unappealing vertical artifacts when using a terrain along with a transparent background (#7523) (by @safwat-halaby) - Bundle with Rolldown instead of Rollup (#7555) (by @birkskyum)
- Optimization for Feature State: Replace String-Indexed Object with Array (up to 3.4X speedup) (#7550) (by @xavierjs)
- Expose
getProjectionDatafunction in custom layer args objects (#7471) (by @kubapelc) - Marked package
sideEffectsas CSS-only in package metadata, which may improve tree-shaking and reduce bundle size in some bundlers (#7258) (by @CommanderStorm)
🐞 Bug fixes
⚠️ Fix transparent, overlapping lines creating artefacts. This is fixed forline-opacity, but purposefully not for transparentline-colorproperties, thus still allowing transparent colors to stack their effect. (#7490) (by @CommanderStorm)⚠️ Disable icon scaling with offset, this is a render breaking change which we have decided to incorporate in both maplibre-gl-js and maplibre-native (#7742) (by @springmeyer and @HarelM)- Log style validation warnings instead of treating them as errors, so that a filter mixing legacy and expression syntax no longer aborts the style load and blanks the map (#7941) (by @HarelM)
- Validate
raster-demsources passed tomap.addSource, which were previously skipped. Stop a source type the style spec has no schema for, such as one registered withaddSourceType, from failing the whole style. Previously onlycanvaswas let through (#7941) (by @HarelM) - Fix
line-layer-opacity/fill-layer-opacityclipping away a subsequent layer that shares the same source (#7867) (by @CommanderStorm) - Fix camera jump in flyTo when minZoom is set (#7743) (by @YuChunTsao)
- Fix stale terrain depth and coordinate framebuffers when terrain tiles change without camera movement (#7812) (by @DoFabien)
- Fix a memory leak where aborting a worker request (e.g. a GeoJSON tile load cancelled while panning) left its promise pending forever, so the awaiting async frame and everything it captured was never released;
Actor.sendAsyncnow rejects with anAbortErroron abort (#7826) (by @kamil-sienkiewicz-asi) - Skip
undefinedproperties during worker serialization (#7801) (by @xavierjs) - Fix cross-origin module worker loading to preserve ESM semantics (#7796) (by @dangkyokhoang)
- Fix conflicting reloads of tiles causing an error in
queryRenderedFeatures(#7765) (by @ckolin) - Fix a race condition in geojson source after init and fast update data (#7734) (by @HarelM)
- Fix camera jump on dragend with globe + terrain at low pitch (#7736) (by @kodeezabdullah)
- Fix web font rendering by awaiting document.fonts.load() before TinySDF instantiation (#7735) (by @kodeezabdullah)
- Remove the framebuffer completeness check that threw an unhandled
Framebuffer is not completeerror on transient GPU resource loss (e.g. when a tab wakes from sleep); incomplete framebuffers now self-heal on the next frame instead (#7303) (by @johanrd) - Fix handling cross-origin blob URL in Ajax utils (#7675) (by @katemihalikova)
- Avoid TypeErrors from style methods while the WebGL context is lost (#7710) (by @cyphercodes)
- querySourceFeatures() throws 'Block overruns tile' on overzoomed MLT tiles because the reported encoding doesn't match the re-encoded MVT data (#7707) (by @ted-piotrowski)
- Fix geometry length check for polygons and lines in LineBucket after duplicate vertex trimming(#7638) (by @widefire)
line-dasharraystep transition lags one zoom level when the step's branches are data-driven (#7705) (by @lucaswoj)- Fix feature state bulk remove + feature set per-id set does not remove state of first feature (#7554) (by @xavierjs)
- Remove error when actor doesn't have a registered message type for better usability of custom messages in workers (#7589) (by @HarelM)
- Auto-load worker module for CDN usage (#7595) (by @birkskyum)
- Fix Large number of feature state keys leads to zoom lag when loading cached tiles (#7590) (by @xavierjs)
- Fix issue when map's max zoom and source max zoom are close to eachother (#7567) (by @HarelM)