Mapbox Style JSON — declarative vector map styling: specification and applications
Mapbox Style Specification is a JSON schema that declaratively describes how a browser or mobile app should paint vector tiles. The style.json file does not draw anything by itself: it simply states "this road is a 1.5 px grey line on zoom levels 10 to 14, and that shop label is a symbol in Open Sans Bold at 12 pixels". The Mapbox GL JS or MapLibre GL JS engine reads the spec and renders pixels via WebGL into a <canvas>. For a developer this means: a single file fully defines map appearance, and it can be edited in a text editor or generated programmatically — for thematic overlays or brand-aligned base maps alike.
History: from Mapbox Studio to an open spec
Mapbox Inc. was founded in 2010 in Washington, DC by engineers Eric Gundersen, Will White, and Tom MacWright. Early years revolved around raster tiles atop OpenStreetMap, competing with Google Maps in the niche of "your own" maps for media and startups. The turning point came in 2014: Mapbox released Mapbox GL JS, a WebGL library that drew maps not from pre-rendered PNG tiles but from vector MVTs directly in the browser. That changed the game — a site could now restyle a map on the fly without server-side tile regeneration.
The new technology needed a new file format. Before GL JS, map styles were described in CartoCSS — a CSS dialect over Mapnik, inherited from Mapbox Classic and OSM Carto. That wouldn't work for WebGL: a fast-to-parse, shader-friendly format was needed. So Mapbox Style Specification was born, JSON-based. Version 1 dates back to 2014, version 8 is the current stable release from 2016, and "Mapbox Style v8" is what people refer to today.
For a long time the spec was open and BSD-licensed — anyone could take a style.json file and use it with their own renderer. In December 2020 Mapbox released GL JS v2 under a proprietary license, requiring a Mapbox API token even for self-hosted apps. That triggered a community fork — MapLibre GL JS, which continued the v1.13 line under BSD and has its own article in this series. Nonetheless, the Mapbox Style v8 spec itself remains formally readable — Mapbox publishes it at docs.mapbox.com/style-spec and continues evolving it in its own directions (3D models, fog, projection, custom layers in Mapbox v3).
What's inside style.json
style.json is a flat JSON object with a fixed set of top-level keys. The four most important are version, sources, sprite, layers.
version is an integer; for all modern styles it is 8. This is not the version of your file but the version of the specification itself. The parser uses this number to decide which features it can recognize.
sources is a dictionary of data sources. The key is an arbitrary source name; the value is an object with a type and a URL. Six source types exist: vector for MVT tiles, raster for raster PNG/JPEG tiles, raster-dem for elevation tiles, geojson for direct GeoJSON loading, image for image overlays on coordinates, and video for video overlays. Each source carries metadata — tiles (an array of URL templates), or url (a TileJSON link), or data (for GeoJSON).
sprite is a URL pointing to a sprite file — a single PNG with all POI icons (metro, bus stop, café, parking) and a JSON index of coordinates. The sprite lives separately from the style and is fetched in parallel on first render.
glyphs is a URL template to PBF font glyph files. Mapbox uses SDF (signed distance field) fonts to render labels at any zoom without re-rasterization. The template typically looks like https://example.com/glyphs/{fontstack}/{range}.pbf.
layers is an array of layers. This is the heart of the spec: each element describes what and how to draw. Required fields per layer are id (unique identifier), type (one of 14 render types), and usually source referencing a data source. Layer types: background, fill, line, symbol, raster, circle, fill-extrusion (3D buildings), heatmap, hillshade, model (Mapbox v3), sky, clip, slot, custom. Each type has its own paint (color, opacity, width) and layout (visibility, text alignment, icon placement) properties.
Optional top-level fields: light controls lighting for fill-extrusion, terrain plugs DEM data in as 3D relief, fog paints atmospheric haze on the horizon, projection switches between Web Mercator, globe, and other projections (Mapbox v3+).
Within paint and layout you can use not just constants but expressions — Mapbox's typed expression language. It's a mini-language described in JSON with its own functions: ["interpolate", ["linear"], ["zoom"], 10, 1, 16, 4] means "width grows linearly from 1 at zoom 10 to 4 at zoom 16". Available are get, has, case, match, all, any, step, format, concat, and dozens of others. This lets one style adapt to data and scale without duplicating layers.
Who needs Mapbox Style JSON: five roles
Web developer with brand identity. A startup builds a scooter-sharing app and wants the map to look distinctive — muted grey buildings, purple highlights on bike lanes, branded fonts. CartoCSS under Mapnik would require running your own tile server; with Style JSON the entire branding fits into a single file deployable on any CDN.
Freelance cartographer. A client requests "a map that looks like New York Times, but for a Russian region." Open Maputnik, import a style.json from Stadia or Stamen, tweak layer colors by hand in the visual editor, export back — and hand over the file with instructions on plugging it into the client's renderer.
Data scientist. Work constantly involves showing spatial data with different attributes over a base map. A GeoJSON source plus a couple of layers with expression-filters on feature properties — and the same base map shows population density, then crime, then ML predictions. Switching between visualizations is a paint-property swap with no tile redraw.
Educator. A university course in web cartography needs students to grasp how a map is assembled from layers. Style.json is teaching artifact number one: sources are visible (where data comes from), layers are visible (what is drawn in which order), paint is visible (how exactly). In one lecture you can open a working style, remove the label layer, save it, and show the result in the browser.
Embed provider. A service like osm2cdr.ru or a regional tourism portal offers an embeddable map widget for third-party sites. A style.json hosted on the partner's own CDN lets clients override styling logic — make the restaurant layer brighter, mute the road layer — without touching widget code. JSON parameterization is cleaner than dozens of API options.
What to use for editing and hosting: seven tools
Mapbox Studio. Official visual style editor. Drag-and-drop interface, side panel of layers, color pickers per property, full-screen map preview. One-click style.json export. Free tier limited to 50,000 style loads per month. studio.mapbox.com
Maputnik. Open alternative to Mapbox Studio, fully browser-based, no signup. Imports and exports style.json, supports all layer types and expressions, can connect to any tile source. Ideal for adapting third-party styles to your needs. maputnik.github.io
Mapbox GL JS. The browser-side engine library. Takes style.json in its constructor and renders the map via WebGL. Versions through 1.13 — BSD; versions 2.0+ — proprietary license tied to Mapbox API. docs.mapbox.com/mapbox-gl-js
Tippecanoe. Mapbox's MVT generator from GeoJSON. Not a style editor itself but the tool that turns geodata into a source referenced by style.json. Supports zoom-based geometry simplification, attribute dropping, filtering. github.com/felt/tippecanoe (fork now maintained by Felt).
vt2geojson. Mapbox utility for the inverse — converts an MVT tile back into GeoJSON for debugging. Useful when a style isn't showing a layer and it's unclear whether data or paint is at fault. github.com/mapbox/vt2geojson
TileServer GL. A ready-made Node.js server that hosts MVT, renders raster tiles via style.json through headless mapbox-gl-native, and serves TileJSON. Convenient for local development or production. github.com/maptiler/tileserver-gl
mapbox-gl-style-spec npm package. Official validator: npm install -g @mapbox/mapbox-gl-style-spec then gl-style-validate style.json flags every error in the file. Indispensable in a CI pipeline when the style is generated automatically.
Pitfalls and tips
Array order determines paint order. The first element is drawn first (at the bottom), the last on top. If the label layer ends up below the building layer, labels disappear. This is the usual "where did my labels go" cause when editing by hand.
source-layer is required for vector sources. Each MVT tile contains multiple internal layers (roads, buildings, water…), and in the style you must explicitly name which one a given layer block references. Forgetting source-layer silently fails to render.
Expressions are strongly typed. Mapbox v8 enforces types: ["get", "population"] returns a string if the source field is stored as string. To use it in interpolate, wrap with ["to-number", ...]. This kind of error only shows up in the browser console.
SDF fonts are limited. Only fonts present on your glyph server are available. By default Mapbox serves Open Sans, Klokantech Noto Sans, and a couple of others. Specifying text-font: ["Roboto Bold"] without serving Roboto glyphs results in missing labels. Solution: generate pbf via github.com/openmaptiles/fonts or stick to available fonts.
Mapbox v1, v2, v3 diverged from MapLibre. Mapbox v3 added the model layer for 3D objects, slot-based composition, and Mapbox Standard as the default style. MapLibre has its own projection: globe and terrain features. A style authored in Mapbox Studio v3 may require removing Mapbox-specific layer types before working in MapLibre.
style.json grows fast. Real production styles (Mapbox Streets v12, OpenMapTiles Bright) are 200–500 KB files with 200+ layers and complex expressions. Performance is fine (JSON parses quickly), but hand-editing becomes impractical. Use Maputnik or generate programmatically.
Not all clients are equal. Mapbox GL JS, MapLibre GL JS, mapbox-gl-native, MapLibre Native, react-map-gl, deck.gl all read style.json, but feature support differs. fog exists in Mapbox GL JS v2+; MapLibre lacks it. model is Mapbox v3 only. Verify style compatibility against your target renderer.
How to author a style for your data via osm2cdr.ru
osm2cdr.ru generates vector tiles in PMTiles — a single-file MVT archive hostable on any static server. Your style references this file via the PMTiles protocol. Steps:
Step 1. On osm2cdr.ru outline the area (from neighborhood to whole country), choose PMTiles or MVT in the format dropdown, download. Step 2. Upload the .pmtiles to your hosting — S3, Cloudflare R2, GitHub Pages, or your own nginx with proper Range-headers. Step 3. Write a minimal style.json:
{
"version": 8,
"name": "OSM2CDR Custom",
"sources": {
"osm-vector": {
"type": "vector",
"url": "pmtiles://https://yoursite.com/area.pmtiles"
}
},
"glyphs": "https://fonts.openmaptiles.org/{fontstack}/{range}.pbf",
"layers": [
{"id": "background", "type": "background",
"paint": {"background-color": "#f8f4f0"}},
{"id": "water", "type": "fill", "source": "osm-vector",
"source-layer": "water",
"paint": {"fill-color": "#a0c8e0"}},
{"id": "buildings", "type": "fill", "source": "osm-vector",
"source-layer": "buildings",
"paint": {"fill-color": "#e0d0c0", "fill-outline-color": "#c0b0a0"}},
{"id": "roads", "type": "line", "source": "osm-vector",
"source-layer": "roads",
"paint": {"line-color": "#555",
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.5, 16, 3]}}
]
}
Step 4. Wire it into the browser via MapLibre GL JS with the PMTiles protocol plugin:
import maplibregl from 'maplibre-gl';
import { Protocol } from 'pmtiles';
const protocol = new Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);
const map = new maplibregl.Map({
container: 'map',
style: '/style.json',
center: [37.62, 55.75],
zoom: 12
});
Step 5. Open style.json in Maputnik, adjust colors and widths to taste, export back. No server required — everything works statically.
Related formats and resources
- MVT — Mapbox Vector Tile binary format
- PMTiles — single-file vector tiles archive
- MBTiles — SQLite-based tile container
- GeoJSON — JSON-based vector exchange
- TileJSON — metadata descriptor for tile sources
- MapLibre Style Spec — open-source fork
Sources
- Mapbox Style Specification v8 — docs.mapbox.com/style-spec
- Mapbox GL JS documentation — docs.mapbox.com/mapbox-gl-js
- Mapbox Style Spec on GitHub (legacy v1.13, BSD) — github.com/mapbox/mapbox-gl-style-spec
- Maputnik visual editor — maputnik.github.io
- Tippecanoe MVT generator — github.com/felt/tippecanoe
- PMTiles protocol — github.com/protomaps/PMTiles