Documentation menu
Migrating from Mapbox
Most of a Mapbox GL JS map moves across with the renderer swapped and the
URLs changed, because MapMap renders with MapLibre GL JS, which began as a
fork of Mapbox GL JS and still shares its style specification and most of
its API. addSource, addLayer, expressions, queryRenderedFeatures and
feature-state are the same calls with the same arguments. What changes is
narrow and knowable: the style URL, the mapbox:// source URLs, the
newer Mapbox-only conveniences (slots, interactions, Standard style config)
and where your hosted tilesets live. This page is that list, gaps
included. Routing, geocoding and the other APIs are covered in
migrating from Mapbox: what changes and what does not.
Keys
A Mapbox pk. token becomes a MapMap snk_ key, issued by one
unauthenticated call with no card:
curl -fsS -X POST "https://api.mapmap.ai/v1/keys" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "accept_tos": true}'
createMap takes it as apiKey. For URL-only contexts (a style URL handed
to a native SDK) it travels as ?api_key=snk_….
The map: style URL to createMap
// Before
import mapboxgl from "mapbox-gl";
mapboxgl.accessToken = "pk.…";
const map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/streets-v12",
center: [-0.1278, 51.5074],
zoom: 12,
});
// After
import { createMap } from "@mapmap/maps";
import "maplibre-gl/dist/maplibre-gl.css";
const map = createMap({
container: "map",
apiKey: "snk_…",
style: "light", // "light" | "dark" | a Studio theme | a style URL
center: [-0.1278, 51.5074],
zoom: 12,
});
await map.whenReady();
npm install @mapmap/maps maplibre-gl pmtiles
map.map is the underlying MapLibre map. Everything you used to call on
your Mapbox map object you now call on map.map; the SDK's own helpers
(RouteLayer, PlacesLayer, Geocoder and the rest) sit beside it. If you
construct a maplibregl.Map yourself instead, import MapLibre as
import * as maplibregl from "maplibre-gl": MapLibre 6 has no default
export.
The container needs an explicit height, exactly as before.
Sources: mapbox:// to pmtiles:// or your own tiles
Every mapbox:// URL in a style or an addSource call has to change,
because it resolves only against Mapbox's servers.
| Mapbox | MapMap |
|---|---|
mapbox://styles/mapbox/streets-v12 and the other Mapbox styles | style: "light" or "dark", a Studio theme, or a hosted style URL from POST /styles |
mapbox://mapbox.mapbox-streets-v8 (the basemap vector tiles) | Comes with the style. To reference it yourself: GET /tiles/{territory}/tiles.json. The schema is OpenMapTiles, so layer and property names differ from Mapbox Streets |
mapbox://your-user.your-tileset (an uploaded tileset) | A PMTiles file on your own bucket: url: "pmtiles://https://your-bucket.example.com/your-data.pmtiles". See Bring your own tiles |
mapbox://mapbox.satellite | Your own imagery as an XYZ raster source. MapMap does not offer a hosted satellite tileset for your apps |
mapbox://mapbox.mapbox-terrain-dem-v1 | terrain: true on createMap, which drapes the map over the same DEM the gateway answers POST /elevation from |
GeoJSON, image, video and raster sources with https URLs | Unchanged |
Because the basemap schema is OpenMapTiles rather than Mapbox Streets, a
filter written against Streets property names (for example class
values or maki icons) needs checking against the
styleable layer ids. Your own data layers
are unaffected.
addLayer(..., beforeId) and slots
Mapbox Standard puts your layers into named slots (bottom, middle,
top). MapLibre has no slots; you pass the id of the layer to insert
beneath, which is what Mapbox did before Standard and still accepts. The
MapMap styles share one layer skeleton, so the three slots map to three
fixed layer ids, listed in the
insertion points table:
// Mapbox Standard
map.addLayer({ id: "zones", type: "fill", source: "zones", slot: "middle" });
// MapMap today
map.map.addLayer({ id: "zones", type: "fill", source: "zones" }, "road-oneway");
Slots arrive in the SDK 0.17 under the same names: map.slot("middle")
returns the layer id to pass, resolved against the live style so a Studio
theme that drops a layer still works.
addInteraction and featuresets
map.addInteraction and the Standard featuresets (poi, place-labels,
buildings) are Mapbox only. On MapLibre the same behaviour is the older
pattern, which Mapbox still supports too: layer-scoped events plus
feature-state.
// Mapbox
map.addInteraction("zone-click", {
type: "click",
target: { layerId: "zones" },
handler: (e) => console.log(e.feature),
});
// MapMap today
map.map.on("click", "zones", (e) => console.log(e.features?.[0]));
The SDK adds an addInteraction helper in 0.17, shaped like Mapbox's, with
the poi, place-labels and buildings featureset ids mapped onto the
MapMap layers. Until then, hover highlight with feature-state
and click a feature for a popup are the
patterns to copy.
What does not change
queryRenderedFeaturesandquerySourceFeatures: same signatures, same results shape.- feature-state:
setFeatureState,getFeatureState,removeFeatureState,promoteIdand the["feature-state", …]expression are the same. One difference to plan for: MapMap basemap features carry tile-assigned ids, not OpenStreetMap ids, so state on basemap layers is per tile. Your own sources behave as before. - Expressions and data-driven styling, clustering with
clusterProperties, heatmaps, fill-extrusion,line-gradientwithlineMetrics, image and video sources, custom WebGL layers, terrain and the globe projection. - Popups and markers:
new maplibregl.Popup()andnew maplibregl.Marker()replace theirmapboxglnamesakes one for one.
The examples gallery has fifteen runnable data-layer samples written against exactly this surface.
Standard style config to Studio themes and global-state
Mapbox Standard exposes runtime config (setConfigProperty("basemap", "lightPreset", "dusk"), show or hide POI labels, theme colours). On
MapMap the design lives in a Studio theme: 19 palette slots, per-layer
overrides, POI and marker designs, saved as a theme document and
published as a hosted style. Switch between themes at run time with
setStyle, or let ThemeScheduler swap day and night on sun times.
For your own layers, MapLibre's global-state expression is the closest
thing to Mapbox's config expression: declare a value once, read it in
any paint or filter expression with ["global-state", "name"], and change
it with map.map.setGlobalStateProperty("name", value).
What MapLibre does not have
Stated plainly, so a gap does not surface halfway through a migration.
Raster-array sources and the raster particle layer, model layers
(model and 3D landmarks), the snow and rain layers, multiple lights and
style imports are not available, and we make no promise that they will
be. There is no addInteraction and no featuresets in MapLibre itself
(the SDK helper above covers the common case). Video sources are MapLibre
GL JS only: MapLibre Native on iOS and Android has none. Going the other
way, MapLibre has a color-relief layer for colouring elevation, which
Mapbox does not.
Studio uploads to your own hosting
Mapbox Studio uploads a dataset, tiles it on Mapbox's servers and hosts the tileset. MapMap has no hosted tileset upload, by decision: we do not hold customer datasets. The route is bring your own hosting:
- Tile on your own machine. The self-host distro ships
snfactory tile your-data.geojson -o your-data.pmtiles --layer your-data; any PMTiles writer works. - Put the file on your own bucket (S3, R2, GCS, Azure) with range requests and CORS on.
- Reference it as
pmtiles://https://…in your style or anaddSourcecall.
Small datasets need none of that: a GeoJSON URL in an addSource call is
fetched by the browser directly. Point datasets you want searchable (a
store finder, places along a route) go to PUT /places, up to 10,000 per
key. The full walk-through is on add your own data.
Pricing
From /pricing.json, which is always the source of truth
over this page. Prices are in pounds sterling and prepaid: a key stops at
its limit rather than running up an invoice.
- Free tier: 50,000 calls a month on an email-verified key, no card, commercial use allowed. A new key works immediately for 1,000 calls before verification.
- Map tiles are discounted: one call per 50 vector-tile requests, and hosted style reads are public and unmetered.
- Standard calls (geocoding, car and other non-truck routing, matrix, isochrones) are 0.05p each from call 50,001 to 1 million, 0.03p to 10 million and 0.02p beyond.
- Monthly plans: Starter £49 (250,000 calls), Growth £299 (2 million), Scale £1,250 (10 million).
- Tiles you host yourself cost nothing on MapMap: a PMTiles file on your bucket is read by the browser straight from your storage and never passes through the gateway.
Next steps
- Add your own data: every source type, insertion points, feature-state and the native snippets
- Examples: copy-and-run samples for each pattern on this page
- Web maps: styles, Studio themes and the layer ids
- Migrating from Mapbox: routing and APIs: endpoint mapping, the error model and the honest gap list