Mapbox GL JS: Choosing Between Vector Tiles and GeoJSON for High-Density Data
Learn when to use Vector Tiles versus GeoJSON sources in Mapbox GL JS to maintain 60fps performance when visualizing high‑density geographic datasets.
14 May 2026, 14:29 UTC

The Performance Bottleneck in Map Data Rendering
When visualizing thousands of geographic features, the primary technical challenge is maintaining a consistent 60 frames per second (fps) during pan and zoom operations. If the browser’s main thread is blocked by parsing massive data objects or calculating coordinates for too many features, the map will stutter, leading to a poor user experience.
The decision rests on whether you need instant updates for a small set of features or smooth navigation for a massive dataset. Choosing the wrong source type often leads to browser crashes on mobile devices or unresponsive interfaces when datasets scale.
Comparison: Vector Tiles vs. GeoJSON Sources
| Constraint | GeoJSON Source | Vector Tile Source |
|---|---|---|
| Dataset Size | Best for < 10,000 features | Optimized for 10,000+ features |
| Update Frequency | Real‑time (via setData()) |
Static or batch‑updated |
| Client CPU Load | High (parses entire blob) | Low (loads only visible tiles) |
| Initial Load Time | Slow for large files | Fast (incremental loading) |
| Data Precision | Full precision maintained | Simplified based on zoom level |
Engineering Trade‑offs
GeoJSON: Low Latency, High Memory
GeoJSON sources load a single JSON object into the browser’s memory. This is ideal for dynamic dashboards where features change state frequently. Because the data is already present in memory, calling map.getSource('my-data').setData(newData) allows for near‑instant visual updates without network requests.
The Risk: Large GeoJSON files (e.g., >20 MB) can block the main thread during the parsing phase. On mobile browsers, this often results in an "Out of Memory" crash or severe frame drops during interaction.
Vector Tiles: High Scalability, Higher Latency
Vector Tiles slice data into a pyramid structure of small binary files. The client only requests the tiles necessary for the current viewport and zoom level. This offloads the heavy lifting to a tiling service (like Mapbox Tiling Service), ensuring that the browser never processes more data than it can render.
The Risk: Because tiles are pre‑processed, you cannot update a single feature instantly. Changes require re‑uploading the dataset to the tiling service or using a dynamic tile server, which introduces network latency.
Implementation: Dynamic GeoJSON Updates
Use this pattern when you have a medium‑sized dataset that requires real‑time filtering or movement. This example assumes Mapbox GL JS v2.x or v3.x.
// Run in the client‑side browser environment
// Required: Mapbox GL JS library loaded and access token configured
// 1. Initialize the source with an empty GeoJSON object
map.addSource('realtime-points', {
type: 'geojson',
data: { type: 'FeatureCollection', features: [] }
});
// 2. Add a layer to visualize the source
map.addLayer({
id: 'points-layer',
type: 'circle',
source: 'realtime-points',
paint: {
'circle-radius': 5,
'circle-color': '#007cbf'
}
});
// 3. Update the data dynamically
async function updateMapData(apiUrl) {
try {
const response = await fetch(apiUrl);
const data = await response.json();
// Use setData() to update the source without reloading the map
// Risk: Calling this too frequently (e.g., every 100 ms) may cause stuttering
map.getSource('realtime-points').setData(data);
} catch (err) {
console.error('Data update failed:', err);
}
}
Validating Performance
To determine if your GeoJSON source has become a bottleneck, use the Chrome DevTools Performance tab:
- Record a session while panning the map.
- Look for long yellow blocks in the
Mainthread section labeledScripting. - If
setData()or the internal Mapbox parsing functions take longer than 16 ms, you are dropping frames and should migrate to Vector Tiles.
Rollback and State Management
If you migrate from GeoJSON to Vector Tiles and encounter visual popping (where features disappear or change shape abruptly during zoom), you must adjust the maxzoom of the tileset or increase the generalization quality in your tiling pipeline. To revert to GeoJSON, remove the vector source and layer, then re‑add the geojson source using the original JSON endpoint.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.