NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #4928 most downloaded on npm
A WebGL interactive maps library
Last release 5 days ago
29 Sep 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
4 versions withdrawn
withdrawn after publishing
12 years old
299 releases · first in 2014
Nothing published for this version
This patch introduces two workarounds that address longstanding issues related to unbounded memory growth in Safari, including #8771 and #4695. We’ve
This patch introduces two workarounds that address longstanding issues related to unbounded memory growth in Safari, including #8771 and #4695. We’ve identified two memory leaks in Safari: one in the CacheStorage API, addressed by #8956, and one in transferring data between web workers through Transferables, addressed by #9003.
CacheStorage API. ( #8856)Transferable objects to transfer ArrayBuffers to WebWorkers. If GL-JS detetcts that it is running in Safari, the use of Transferables to transfer data to WebWorkers is disabled. ( #9003)map.setData. (#8913) (h/t msbarry)One column per quarter.
Nothing published for this version
Add disabled icon to GeolocateControl if user denies geolocation permission. #8871)
outofmaxbounds event to GeolocateControl, which is emitted when the user is outside of map.maxBounds (#8756) (h/t MoradiDavijani)mapboxgl.getRTLTextPluginStatus() to query the current status of the rtl-text-plugin to make it easier to allow clearing the plugin when necessary. (ref. #7869) (#8864)hash Map option to be set as a string, which sets the map hash in the url to a custom query parameter. (#8603) (h/t SebCorbin)text-variable-anchor not trying multiple placements during collision with icons when icon-text-fit is enabled. (#8803)icon-text-fit not properly respecting vertical labels. (#8835)ArrayBuffers in environments where instanceof ArrayBuffer fails.(e.g cypress) (#8868)Nothing published for this version
Fix the way that coalesce handles the image operator so available images are rendered properly
Add image expression operator to determine image availability
image expression operator to determine image availability (#8684)text-offset with variable label placement (#8642)collisionBox when text-translate or icon-translate is enabled (#8659)TypeError when reloading a source and immediately removing the map (#8711)originalEvent property to NavigationControl events (#8693) (h/t stepankuzmin)Popup#trackPointer before setting its content or location (#8757) (h/t zxwandrew)icon-text-fit are now sized correctly (#8741)icon-text-fit now works correctly (#8741)Nothing published for this version
Nothing published for this version
Fix a SecurityError in Firefox >= 69 when accessing the cache
Fix a race condition that produced an error when a map was removed while reloading a source. #8711
render event was sometimes not fired after load event in IE11. #8708Introduce text-writing-mode symbol layer property to allow placing point labels vertically. #8399
text-writing-mode symbol layer property to allow placing point labels vertically. #8399text/icon-allow-overlap is set to true. #8620text-color to be used in formatted expressions to be able to draw different parts of a label in different colors. #8068map.showTileBoundaries = true. #8380 (h/t @andrewharvey)MercatorCoordinate.meterInMercatorCoordinateUnits method to make it easier to convert from meter units to coordinate values used in custom layers. #8524 (h/t @andrewharvey)mapbox-gl-js-docs repo. #8582esm from package dependencies (so that it's not installed on npm install mapbox-gl). #8586 (h/t @DatGreekChick)Nothing published for this version
Fix bug in NavigationControl compass button that prevented it from rotating with the map
NavigationControl compass button that prevented it from rotating with the map (#8605)…(considered a bug fix, but is technically a breaking change from previous behavior)
*-sort-key layout property for circle, fill, and line layers, to dictate which features appear above others within a single layer(#8467)prefers-reduced-motion settings in browser (#8494)visualizePitch option that tilts the compass as the map pitches (#8208, fixed by #8296) (h/t pakastin)convertFilter API in the style specification (#8493text-variable-anchor, such that previous anchor positions would take precedence only if they are present in the updated array (considered a bug fix, but is technically a breaking change from previous behavior) (#8473)startPos is not defined (#8462) (h/t @msbarry)baseAPIURL of a certain form (#8466)Nothing published for this version
Fix unbounded memory growth caused by failure to cancel requests to the cache
Improve line rendering performance by using a more compact line attributes layout
queryRenderedFeatures and querySourceFeatures calls, as a performance optimization (#8211) (h/t gorshkov-leonid)setFilter performance by caching keys in groupByLayout routine (#8122) (h/t vallendm)symbol-z-order: viewport-y, when icons are allowed to overlap but not text (#8180)WebGLRenderingContext argument to onRemove function of CustomLayerInterface, to allow direct cleanup of related context (#8156) (h/t ogiermaitre)setZoomRate and setWheelZoomRate methods to ScrollZoomHandler (#7863) (h/t sf31)trackPointer method to Popup API that continuously repositions the popup to the mouse cursor when the cursor is within the map (#7786)getElement method to Popup to retrieve the popup's HTML element (#8123) (h/t bravecow)fill-pattern example to the documentation (#8022) (h/t flawyte)nofollow to Mapbox logo & "Improve this map" links (#8106) (h/t viniciuskneves)updateImage not working as expected in Chrome (#8199)movestart events when zooming (#8259) (h/t bambielli-flex)"format" expression failing when options are provided (#8339)setPaintProperty not working on line-pattern property (#8289)findStopLessThanOrEqualTo algorithm (#8134) (h/t Mike96Angelo)text-align: center (#8227) (h/t mc100s)Popup#maxWidth accepts all max-width CSS values (#8312) (h/t viniciuskneves)Nothing published for this version
Nothing published for this version
This release replaces the existing “map views” pricing model in favor of a “map load” model. Learn more in a recent blog post about these changes.
This release replaces the existing “map views” pricing model in favor of a “map load” model. Learn more in a recent blog post about these changes.
By upgrading to this release, you are opting in to the new map loads pricing.
Why is this change being made?
This change allows us to implement a more standardized and predictable method of billing GL JS map usage. You’ll be charged whenever your website or web application loads, not by when users pan and zoom around the map, incentivizing developers to create highly interactive map experiences. The new pricing structure also creates a significantly larger free tier to help developers get started building their applications with Mapbox tools while pay-as-you-go pricing and automatic volume discounts help your application scale with Mapbox. Session billing also aligns invoices with metrics web developers already track and makes it easier to compare usage with other mapping providers.
What is changing?
When (and only when) loading tiles from a Mapbox API with a Mapbox access token set (mapboxgl.accessToken), a query parameter named sku will be added to all requests for vector, raster and raster-dem tiles. Every map instance uses a unique sku value, which is refreshed every 12 hours. The token itself is comprised of a token version (always “1”), a sku ID (always “01”) and a random 10-digit base-62 number. The purpose of the token is to allow for metering of map sessions on the server-side. A session lasts from a new map instantiation until the map is destroyed or 12 hours passes, whichever comes first.
For further information on the pricing changes, you can read our blog post and check out our new pricing page, which has a price calculator. As always, you can also contact our team at https://support.mapbox.com.
Fix unbounded memory growth caused by failure to cancel requests in IE
Turned localIdeographFontFamily map option on by default. This may change how CJK labels are rendered, but dramatically improves performance of CJK ma
localIdeographFontFamily map option on by default. This may change how CJK labels are rendered, but dramatically improves performance of CJK maps (because the browser no longer needs to download heavy amounts of font data from the server). Add localIdeographFontFamily: false to turn this off. #8008Popup maxWidth option, set to "240px" by default. #7906mapbox-gl-csp.js bundle for strict CSP environments where worker-src: blob is disallowed. #8044"visibility": "visible". #8005canvasSource.pause to be more reliable and able to render a single frame. #8130rel="noopener" attributes to links that lead to external websites (such as Mapbox logo and OpenStreetMap edit link) for improved security. #7914map.showTileBoundaries is turned on. #7963Uncaught TypeError: e is not a function error in the console. #7988removeFeatureState didn't remove the state for tiles on other zoom levels. #8087removeFeatureState didn't work on features with id equal to 0. #8150source.setData(url) many times. #8035map.getCenter() returned a reference to an internal LngLat object instead of cloning it, leading to potential mutability bugs. #7922Nothing published for this version
Nothing published for this version
Turn off telemetry for Mapbox Atlas
Enable fill-extrusion querying with ray picking
fill-extrusion querying with ray picking (#7499)clusterProperties option for aggregated cluster properties (#2412, fixed by #7584)fitBounds options. (#7681) (h/t elyobo)Map#remove (#7749) (h/t andycalder)Map#removeFeatureState (#7761)number-format expression (#7626)symbol-sort-key style property (#7678)file:// protocol in XHR requests for Cordova/Ionic/etc (#7818)LngLat.toBounds() default radius to 0 (#7722, fixed by #7723) (h/t cherniavskii)feature-state dependent layers (#7523, fixed by #7790)map.repaint from mistakenly enabling continuous repaints (#7667)Nothing published for this version
Canonicalize tile urls to mapbox:// urls so they can be transformed with config.API_URL
mapbox:// urls so they can be transformed with config.API_URL (#7594)config.API_URL (#7594)Nothing published for this version
Nothing published for this version
Add initial bounds as map constructor option (#5518) (h/t stepankuzmin)
MercatorCoordinate type (#7488)contextmenu to be enabled (#2301, fixed by #7369)LngLat conversion from {lat, lon} (#7507) (h/t bfrengley)hash within iframes in IE11 (#7411)Nothing published for this version
🎉 Add Custom Layers that can be rendered into with user-provided WebGL code
concat expression and text-field property (#6190, fixed by #7280)fill-extrusion-vertical-gradient property for controlling shading of fill extrusions (#5768, fixed by #6841)ImageSource (#4050, fixed by #7342) (h/t dcervelli)log2 and log10 in IE11 (#7318, fixed by #7320)let expression stripping expected type during parsing (#7300, fixed by #7301)literal expression (#7336, fixed by #7337)to-color on values that are already of type Color (#7260)to-array for empty arrays ((#7261))text-field when using formatted text (#7351)null to 0 in to-number expression (#7083, fixed by #7274)loaded after certain runtime styling changes when there were errored tiles in the viewport (#7355)*-allow-overlap: true when panning into the viewport (#7172, fixed by#7244)mouseover event (#7295, fixed by #7299)getImage if an SVG is requested (#7312, fixed by #7313)Nothing published for this version
Use client{Height/Width} instead of offset{Height/Width} for map canvas sizing (#6848, fixed by #7128)
September 6, 2018
client{Height/Width} instead of offset{Height/Width} for map canvas sizing (#6848, fixed by #7128)icon-allow-overlap: true, text-allow-overlap: true, text-optional: false would show icons when they shouldn't (#7041)gl-style-migrate script to include conversion of legacy functions and filters to their expression equivalents (#6927, fixed by #7095)icon-size for small data-driven values (#7125)Performance updates:
symbol-z-order symbol layout property to style spec (#7219)*-pattern properties (#6289)Map#fitScreenCoordinates which fits viewport to two points, similar to Map#fitBounds but uses screen coordinates and supports non-zero map bearings (#6894)Map#setFeatureState and Map#getFeatureState to accept numeric IDs (#7106) (h/t bfrengley)Nothing published for this version
Treat tiles that error with status 404 as empty renderable tiles to prevent rendering duplicate features in some sparse tilesets
text-max-angle property was being calculated incorectly internally, causing potential rendering errors when "text-placement": linefeature.id when using Map#setFeatureState (#6974)GeolocateControl when user location is being used (#6977) (h/t sergei-zelinsky)Map#querySourceFeatures was returning bad results on zooms > maxZoom (#7061)queryPadding for all layers in a source was set by the first layer, causing incorrect querying on other layers and, in some cases, incorrect firing of events associated with individual layers (#6909)Map#setFeatureState API (#7043)) (#7091)"format" expression (#6994)Add configurable drag pan threshold (#6809) (h/t msbarry)
raster-resampling raster paint property (#6411) (h/t andrewharvey)symbol-placement: line-center (#6821)Nothing published for this version
Align implicit type casting behavior of match expressions with with case/==
match expressions with with case/== (#6684)Map#setFeatureState and feature-state expression to support interactive styling (#6263)Marker with setDraggable (#6687)Map#listImages for listing all currently active sprites/images (#6381)text/icon-rotate for symbols with symbol-placement: point (#6075)collectResourceTiming: true in web workers (#6721)collectResourceTiming: true generates error on iOS9 Safari, IE 11 (#6690)lineMetrics=true only rendered first line (#6649)a element does not open the url when clicked (#6730)setRTLTextPlugin fails with relative URLs (#6719)Nothing published for this version
Evented#fire and Evented#listens are now marked as private. Though Evented is still exported, and fire and listens are still functional, we encourage
Evented#fire and Evented#listens are now marked as private. Though Evented is still exported, and fire and listens are still functional, we encourage you to seek alternatives; a future version may remove their API accessibility or change its behavior. If you are writing a class that needs event emitting functionality, consider using EventEmitter or similar libraries instead."to-string" expression operator now converts null to an empty string rather than to "null". #6534line-gradient property #6303abs, round, floor, and ceil expression operators #6496collator expression for controlling case and diacritic sensitivity in string comparisons #6270raster-dem tilesets #6103Map#isZooming and Map#isRotating methods #6128, #6183raster-dem sources #6110preventDefault method on mousedown, touchstart, and dblclick events #6218originalEvent property on zoomend and moveend for user-initiated scroll events (h/t @stepankuzmin) #6175value in "length" expressions #6244MapWheelEvent#6237ScaleControl units (h/t @ryanhamley) #6138, #6274open event for Popup #6311"object" type assertions are no longer required when using expressions #6235anchor option to Marker #6350HTMLElement is now passed to Marker as part of the options object, but the old function signature is still supported for backwards compatibility #6356Marker SVG element (h/t @andrewharvey) #6416CanvasSource initialization from HTMLElement #6424is-supported-script expression 6260raster-dem tiles to pixel grid to eliminate blurry rendering on some devices #6059Map#queryRenderedFeatures bugs:
{text, icon}-offset when querying#6135circle layer features with -pitch-scaling: 'viewport' or -pitch-alignment: 'map' #6036Map hash #6140Map#addLayer is invoked with an id of a preexisting layer #6147icon-image would not be rendered if text-field is an empty string #6164rotatestart and rotateend events #6187DragHandler bugs where a left-button mouse click would end a right-button drag rotate and a drag gesture would not end if the control key is down on mouseup #6193{DragPanHandler, DragRotateHandler}#disable while a gesture is in progress #6232GeolocateControl user location dot sizing when Map's <div> inherits box-sizing: border-box; (h/t @andrewharvey) #6227array expression error messages (h/t @drewbo) #6269line-width larger than the sprite height of the line-pattern property would render other sprite images #6246DragPanHandler on mobile using Edge (note that zoom/rotate/pitch handlers still do not support Edge touch events #1928) #6325VectorTileWorkerSource#reloadTile causing a rendering timeout #6308gl.stencilFunc calls due to incorrect state checking (h/t @yangdonglai) #6330mousedown or touchstart would cancel camera animations in non-interactive maps #6338text-translate #6365to-rgba expression causing division by zero 6388*-pattern properties with non-integer zoom stops #6430Map#remove on a map with constructor option hash: true throws an error (h/t @allthesignals) #6490Map#moveLayer(layerId, beforeId) to remove the layer when layerId === beforeId #6542Map#querySourceFeatures to throw an Uncaught TypeError(https://github.com/mapbox/mapbox-gl-js/pull/6555)Nothing published for this version
Workaround a breaking change in Safari causing page to scroll/zoom in response to user actions intended to pan/zoom the map #6095. (N.B., not to be co…
Fix bug causing features from symbol layers to be omitted from map.queryRenderedFeatures() #6074
Due to bug fixes #6005 and #6029, DragPanHandler, DragRotateHandler, and ScrollZoomHandler now fire map movement events (move, rotate, zoom, pitch) on
DragPanHandler, DragRotateHandler, and ScrollZoomHandler now fire map movement events (move, rotate, zoom, pitch) only once per render frame, rather than once per mouse/touch event. (See also issue #6047.)script-src 'unsafe-eval' #559LngLatBounds#isEmpty() method #5917collectResourceTiming option to the enable collection of Resource Timing data for requests that are made from Web Workers. (#5948)== and != expressions #5947renderWorldCopies #5932Map#remove() #5943, #5951GeoJSONSource#setData() caused labels to fade out and back in (#6002)move events to be fired out of sync with actual map movements (#6005)Map did not fire mouseover events (#6000] (h/t @jay-manday)It is now an error to attempt to remove a source that is in use #5562
before parameter to moveLayer does not exist #5679"colorSpace": "hcl" now uses shortest-path interpolation for hue #5811raster-dem source type and hillshade layer type #5286Map#hasImage #5775== and != expressions #5840coalesce expressions more useful #5755supported() now returns false on old IE 11 versions that don't support Web Worker blob URLs #5801to-rgba and rgba expressions #5778, #5866*-pattern and line-dasharray #5791colorSpace function property #5843Nothing published for this version
Fix an issue with the scale control being too wide #5715
Workaround for map flashing bug on Chrome 62+ with Intel Iris Graphics 6100 cards #5704
map.showCollisionBoxes is set to false #5673heatmap-color #5682history.replaceState error #5613Improve validation to catch uses of deprecated function syntax #5667
heatmap-color use expressions instead of stop functions #5624{tokens} in expressions for text-field and icon-image #5599curve expression into step and interpolate expressions #5542line-dasharray #5519Map#getLight no longer returns default values; it only returns values explicitly set in the style or at runtime #5682sqrt expression #5493fitBounds when both zooming and padding change #4846queryRenderedFeatures on a heatmap layer #5594queryRenderedSymbols to return results from different sources #5554circle-stroke-width in queryRenderedFeatures #5514circle-stroke-opacity of 0 #5496icon-text-fit with a data-driven text-size #5632position field in GeoJSON #5608Removed support for paint classes #3643. Instead, use runtime styling APIs or Map#setStyle.
Map#setStyle.canvas source contextType option added in 0.40.0 #5449Use setData operation when diffing geojson sources #5332
Return early from draw calls on layers where opacity=0 #5429
A heatmap layer type is now available. This layer type allows you to visualize and explore massive datasets of points, reflecting the shape and density of data well while also looking beautiful. See the blog post for further details.
The value of a style property or filter can now be an expression. Expressions are a way of doing data-driven and zoom-driven styling that provides more flexibility and control, and unifies property and filter syntax.
Previously, data-driven and zoom-driven styling relied on stop functions: you specify a feature property and a set of input-output pairs that essentially define a “scale” for how the style should be calculated based on the feature property. For example, the following would set circle colors on a green-to-red scale based on the value of feature.properties.population:
"circle-color": {
"property": "population",
"stops": [
[0, "green"],
[1000000, "red"]
]
}
This approach is powerful, but we’ve seen a number of use cases that stop functions don't satisfy. Expressions provide the flexibility to address use cases like these:
Multiple feature properties
Using more than one feature property to calculate a given style property. E.g., styling land polygon colors based on both feature.properties.land_use_category and feature.properties.elevation.
Arithmetic
For some use cases it’s necessary to do some arithmetic on the input data. One example is sizing circles to represent quantitative data. Since a circle’s visual size on the screen is really its area (and A=πr^2), the right way to scale circle-radius is square_root(feature.properties.input_data_value). Another example is unit conversions: feature data may include properties that are in some particular unit. Displaying such data in units appropriate to, say, a user’s preference or location, requires being able to do simple arithmetic (multiplication, division) on whatever value is in the data.
Conditional logic This is a big one: basic if-then logic, for example to decide exactly what text to display for a label based on which properties are available in the feature or even the length of the name. A key example of this is properly supporting bilingual labels, where we have to decide whether to show local + English, local-only, or English-only, based on the data that’s available for each feature.
String manipulation More dynamic control over label text with things like uppercase/lowercase/title case transforms, localized number formatting, etc. Without this functionality, crafting and iterating on label content entails a large data-prep burden.
Filters Style layer filters had similar limitations. Moreover, they use a different syntax, even though their job is very similar to that of data-driven styling functions: filters say, “here’s how to look at a feature and decide whether to draw it,” and data-driven style functions say, “here’s how to look at a feature and decide how to size/color/place it.” Expressions provide a unified syntax for defining parts of a style that need to be calculated dynamically from feature data.
For information on the syntax and behavior of expressions, please see the documentation.
Fix bug causing flicker when zooming in on overzoomed tiles #5295
CanvasSource coordinates were flipped and improve performance for non-animated CanvasSources #5303fill-extrusion-height property #5320Map#addImage now requires the image as an HTMLImageElement, ImageData, or object with width, height, and data properties with the same format as Image
Map#addImage now requires the image as an HTMLImageElement, ImageData, or object with width, height, and
data properties with the same format as ImageData. It no longer accepts a raw ArrayBufferView in the second
argument and width and height options in the third argument.canvas sources now require a contextType option specifying the drawing context associated with the source canvas. #5155fill-extrusion layers on the same map #5101icon-anchor property to symbol layers #5183transformRequest option, allowing users to provide a callback that transforms resource request URLs #5021Map#addImage() #5181Marker#getElement() method #5242layer.minzoom #2929center option #5042 (h/t @karthikb351)Map#addLayer() with an inline source would mutate its input #4040NavigationControl triggered mouse events unexpectedly #5148NavigationControl compass caused an error in IE 11 #4784fast-stable-stringify module #5152Marker#togglePopup() failing to return the marker instance #5116Fix packaging issue in 0.39.0 #5025
GeolocateControl breaking changes #4479
GeolocateControl breaking changes #4479
watchPosition has been replaced with trackUserLocationjumpTo (not animated) to fitBounds (animated). An effect of this is the map pitch is no longer reset, although the bearing is still reset to 0.maxZoom can be controlled via the new fitBoundsOptions option (defaults to 15).Markers at their center by default #4751 @andrewharveysignificantRotateThreshold for the TouchZoomRotateHandler #4971, @dagjomarGeolocateControl #4479, @andrewharvey
showUserLocation to draw a "dot" as a Marker on the map at the user's locationtrackUserLocation. When in active lock the camera will update to follow the user location, however if the camera is changed by the API or UI then the control will enter the background state where it won't update the camera to follow the user location.fitBoundsOptions to control the camera operationtrackuserlocationstart and trackuserlocationend eventsLngLat.toBounds method to extend a point location by a given radius to a LngLatBounds objectpackage.json #4809, @tomscholzline-width #4773text-anchor #4997text-justify #5000maxTileCacheSize option #4778, @jczaplewicon-pitch-alignment and circle-pitch-alignment properties #4869 #4871Map#getMaxBounds method #4890, @andrewharvey @lamuertepeludalocalIdeographFontFamily) to use TinySDF to avoid loading expensive CJK glyphs #4895config.API_URL includes a path prepend it to the request URL #4995supercluster version to expose cluster_id property on clustered sources #5002FullscreenControl on unsupported devices #4838, @stepankuzminloadData to the same worker every time #4877load #4870LogoControl logic to update correctly, and hide the <div> instead of removing it from the DOM when it is not needed #4842GeoJSONSource#serialize to include all optionsGlyphSource#getSimpleGlyphs#4992setStyle to reload raster tiles #4852Map#queryRenderedFeatures would error when returning no results #4993Map#areTilesLoaded would always be false on sourcedata events for reloading tiles #4987package.json #4819 @tomscholzAttenuate label size scaling with distance, improving readability of pitched maps #4547
webglcontextlost event #4725 @cdawiflyTo to within the map's specified min- and maxzoom to prevent undefined behavior #4726 @ IvanSanchezflyTo calls #4761queryRenderedSymbols logic to better account for pitch scaling #4792text-keep-upright after text-offset to keep labels upright when intended #4779 [Potentially breaking :warning: but considered a bugfix]aria-label to popup close button #4799 @andrewharveyImprove popup/marker positioning #4577
LngLat#wrapToBestWorldMap#isStyleLoaded and Map#areTilesLoaded events #4321file: protocol #4649 @oscarfontsMap#addImage #4644mapboxgl- prefix on all classes #4584 @asantos3026Replace LogoControl logo with the new Mapbox logo #4598
fill_outline shaders #4600Camera#easeTo interpolation on pitched maps #4540easeTo to cross anti-meridian if the path will be closer, like flyTo #4602flyTo/easeTo not to cross anti-meridian if maxBounds is set #4602style.json in integration testsgl-style-composite is now executable in line with the other tools @andrewharvey #4595gl-style-composite utility now throws an error if a name conflict would occur between layers @andrewharvey #4595fill_outline shaders #4600Camera#easeTo interpolation on pitched maps #4540property's type #4614style.json in integration testsgl-style-composite is now executable in line with the other tools @andrewharvey #4595gl-style-composite utility now throws an error if a name conflict would occur between layers @andrewharvey #4595Your coding agent can read these notes before it upgrades. Set up the MCP server →