On July 22, 2026, the open-source vector map engine MapLibre GL JS officially released v6.0.0. This is not a minor patch. The two most notable changes are: WebGL2 is now mandatory, and the distribution package is ESM only. For projects that still load a single maplibre-gl.js via CDN or maintain WebGL1 compatibility for older browsers, I recommend carefully evaluating this upgrade.

Why Mandatory WebGL2

The official reasoning is that WebGL2 is already widespread and WebGL1 users are very few, so maintaining a dual-stack approach is no longer cost-effective. For applications, the map API usage remains largely unchanged. Modern browsers generally work fine (see Can I use WebGL2), but extremely old devices, environments where GPU access is blocked by policy, or software-only rendering may fail to display the map entirely. When WebGL is unavailable, you can now catch related errors via .on("error"), which makes debugging easier than before. I recommend checking your target users' browser versions before upgrading, especially in scenarios such as government intranets, old Windows systems, or custom browsers.

ESM-only: The End of the UMD Era

v6 only ships ESM packages, with the main file becoming maplibre-gl.mjs (plus a worker). The previous UMD bundle maplibre-gl.js and the dedicated CSP build are no longer provided. For npm, the default import must change from import maplibregl from 'maplibre-gl' to import * as maplibregl from 'maplibre-gl', or use named imports like Map. For CDN usage, you need to replace <script src="...maplibre-gl.js"> with <script type="module"> and then import the module. When bundling with Vite, webpack, or esbuild, you may still need to call setWorkerUrl() once. In pure browser scenarios pulling ESM from a CDN, the worker is usually auto-detected; for cross-origin CDN setups, you typically need to allow blob: in the worker-src directive. In short, this is not just a version number bump. If you are still using very old, non-module page templates, you will need to change the loading method, which represents a significant effort for legacy projects.

Other Breaking Changes

In addition to WebGL2 and ESM, the following incompatible changes deserve attention.

  1. styleimagemissing no longer provides missing images via event callbacks; use Map.setMissingStyleImageResolver instead, which supports both synchronous and asynchronous resolution.
  2. Map now composes a Camera and no longer exposes the internal map.transform; prefer the public API.
  3. Map events are now fully class-based with stricter type constraints; avoid using instanceof checks and differentiate events by their type field instead.
  4. The #pragma mapbox directive in shaders must be changed to #pragma maplibre.
  5. GeoJSONSource.setData has removed the second parameter waitForCompletion and no longer returns this for chaining.
  6. zoomLevelsToOverscale now defaults to 4, which is friendlier for dense labels at high zoom levels, but queryRenderedFeatures may behave slightly differently compared to v5.
  7. The TypeScript compilation target has been raised to ES2022.
  8. The encoding and decoding behavior for nested object properties in GeoJSON has changed; please recheck related property reads and writes.

Feature and Performance Enhancements

Beyond breaking changes, v6 also brings a set of capability and performance improvements.

  1. Added fill-layer-opacity and line-layer-opacity, supporting unified opacity for the entire layer and reducing artifacts when transparent lines overlap.
  2. Terrain rendering performance has been optimized, including shared FBOs, reduced invalid DEM lookups, and texture reuse.
  3. Feature State internal structure has been optimized, yielding about 3.4x speedup in certain scenarios.
  4. Non-power-of-two raster tiles can now use mipmaps, which reduces aliasing at high pitch angles.

There are also many bug fixes, such as memory leaks after aborting worker requests, flyTo jumpiness at minZoom, dragging jumps with globe and terrain at low pitch, and framebuffer errors after waking from sleep.

Summary & Upgrade Advice

For new projects targeting modern browsers, you can adopt v6 directly to minimize future migration costs. For existing projects that need to upgrade and have no browser version concerns, you can follow the migration guide in a test environment to adjust imports and workers, perform focused regression testing, and then deploy. If you still need to support very old terminals or cannot refactor in the short term, you can lock the version to v5 for now. Overall, v6 chooses to abandon legacy platform compatibility and raises the rendering and engineering baseline to the web platform post-2022—a significant shift. In my experience, with such a major version change, if your project is running fine, it is best to hold off for now...

If you have already tried v6 in production, encountered pitfalls, or have ready-made migration snippets, feel free to leave a comment and share.