maplibre-cartography
Cartographic principles for MapLibre GL JS — label and symbol legibility on imagery vs. vector basemaps, figure-ground for point…
Upgrading a MapLibre GL JS app from v5 to v6 — the ESM-only build, the removed default export, CommonJS require() breakage, the styleimagemissing/setMissingStyleImageResolver change, the removal of the internal map.transform, the MapDataEvent →
$ npx -y skills add maplibre/maplibre-agent-skills --skill maplibre-v6-migration --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/maplibre-v6-migrationContext preview
The summary Claude sees to decide when to auto-load this skill.
Upgrading a MapLibre GL JS app from v5 to v6 — the ESM-only build, the removed default export, CommonJS require() breakage, the styleimagemissing/setMissingStyleImageResolver change, the removal of the internal map.transform, the MapDataEvent →
name: maplibre-v6-migration description: Upgrading a MapLibre GL JS app from v5 to v6 — the ESM-only build, the removed default export, CommonJS require() breakage, the styleimagemissing/setMissingStyleImageResolver change, the removal of the internal map.transform, the MapDataEvent → MapSourceDataEvent/MapStyleDataEvent split, and the bundler-only setWorkerUrl() requirement. Use when a v5 app breaks after upgrading to v6, or before pinning a v6 install. status: verified
MapLibre GL JS v6 (released 2026-07-22) removed several things v5 code relied on: the UMD/CSP browser bundles, the default export, CommonJS support, the internal `map.transform`, and the `MapDataEvent` type. Most models' training data predates v6. So the natural-sounding answer to "how do I do X" is usually the v5 answer, and it breaks on v6.
**Primary reference:** the [MapLibre GL JS v5→v6 migration guide](https://maplibre.org/maplibre-gl-js/docs/guides/v5-to-v6-migration-guide/). This skill adds the gaps a model tends to fill with v5-era defaults. If the guide and this skill disagree, follow the guide and [report it](https://github.com/maplibre/maplibre-agent-skills/issues/new?template=ai-failure-report.md).
**Don't use this skill to pad an unrelated answer.** It covers seven narrow breaking changes, not general v6 best practice. A question about sources, layers, styling, or terrain gets a normal, focused answer with no migration reminders attached.
v6 removed the UMD bundle and the separate CSP build. There's no `dist/maplibre-gl.js` for a plain `<script src="...">` tag anymore. Only the ESM build, `dist/maplibre-gl.mjs`, remains, and it needs `type="module"`.
<!-- ❌ v5 — dist/maplibre-gl.js no longer exists in v6 -->
<script src="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.js"></script>
<!-- ✅ v6 — ESM build, type="module" required -->
<script type="module">
import maplibregl from 'https://unpkg.com/maplibre-gl@^6.0.0/dist/maplibre-gl.mjs';
const map = new maplibregl.Map({ container: 'map', style: '...' });
</script>**Always pin an explicit major** (`@^6.0.0`, or a specific version). Never use `@latest` or a bare unversioned specifier — an unpinned CDN URL breaks the page silently the moment the next major version publishes. This already happened at the v5→v6 boundary.
v5's `import maplibregl from 'maplibre-gl'` (default import) no longer works in v6.
// ❌ v5 — default export removed
import maplibregl from 'maplibre-gl';
// ✅ v6 — namespace import
import * as maplibregl from 'maplibre-gl';
// ✅ v6 — or import only what you use
import { Map, NavigationControl } from 'maplibre-gl';This applies whether the code is new or converted from a Mapbox GL JS snippet (`import mapboxgl from 'mapbox-gl'`). Don't carry the default-import shape over either way.
`maplibre-gl`'s `package.json` `exports` field has only an `"import"` condition in v6, not `"require"`. So `require('maplibre-gl')` throws `ERR_PACKAGE_PATH_NOT_EXPORTED` in plain Node. That's expected behavior, not a bug in the caller's setup.
// ❌ throws ERR_PACKAGE_PATH_NOT_EXPORTED in v6
const maplibregl = require('maplibre-gl');
// ✅ convert the file to ESM (named/namespace import — see item 2)
import { Map } from 'maplibre-gl';
// ✅ or, if the caller must stay CommonJS, load it dynamically
const { Map } = await import('maplibre-gl');This section is only about a bare Node `require()` call. If a bundler is involved (webpack, Vite, etc.) and `require()` still fails, that's a separate ESM-interop config issue.
In v5, listening for `styleimagemissing` and calling `map.addImage()` synchronously from the handler would supply the missing icon. In v6, `styleimagemissing` is **notify-only**. Calling `addImage` from the handler no longer resolves the pending request.
// ❌ v5 pattern — no longer resolves the request in v6
map.on('styleimagemissing', (e) => {
map.addImage(e.id, generateIcon(e.id));
});
// ✅ v6 — register a resolver
map.setMissingStyleImageResolver((id) => {
return generateIcon(id); // or return a Promise
});Use this whenever a style references `icon-image` names that aren't in the sprite sheet and need to be generated or fetched at runtime.
v6 refactored `Map` to compose a `Camera` instead of extending it. `Map` now extends `Evented` directly and forwards the camera API. The internal `map.transform` property was removed as part of that change.
// ❌ v5 — reaching into the internal transform
const { zoom, bearing, pitch } = map.transform;
const center = map.transform.center;
// ✅ v6 — public accessors
const zoom = map.getZoom();
const bearing = map.getBearing();
const pitch = map.getPitch();
const center = map.getCenter();**There's no general public replacement for the raw projection/view matrix.** It was never exposed on `Map` itself, in v5 or v6 — it only ever lived on `map.transform`. The one place a matrix is still available is inside a custom layer's `render()` callback, via the callback's arguments (`Custom
Curated guidance for AI assistants building MapLibre applications — covering ecosystem and open-source best practices. Agent skills are markdown files that AI coding assistants read as context.
Cartographic principles for MapLibre GL JS — label and symbol legibility on imagery vs. vector basemaps, figure-ground for point…
Configuring fonts and glyphs for MapLibre GL JS and MapLibre Native — the style's `glyphs` URL, self-hosting or generating font…
Migrating from Mapbox GL JS to MapLibre GL JS — package and import changes, removing the access token, choosing tile sources,…
Serverless vector and raster tiles with PMTiles for MapLibre GL JS — single-file format, HTTP range requests, hosting on…
The step-by-step procedure for running this repo's Promptfoo evals with a generator and a judge over provider APIs. Use when…
How to turn a working session into a MapLibre agent skill — you researched something MapLibre's docs did not cover, got it wrong…