deck.gl
WebGL-powered framework for large-scale data visualization on maps
deck.gl is an open-source WebGL framework for visualizing large geospatial datasets as map overlays. It renders millions of points, arcs, and polygons on top of self-hosted basemaps.
Key features
- WebGL data visualization
- Large dataset rendering
- Map overlay layers
- Works with any basemap
Pros & cons
Strengths
- Renders millions of points
- GPU-accelerated layers
- First-class React support
Trade-offs
- Steep learning curve
- WebGL knowledge helps
deck.gl replaces
Last reviewed Aug 26, 2026 · 787 words
Two million GPS points on a map is a ten-second wait and a frozen tab in Leaflet, and a smooth 60 fps pan in deck.gl. That is the entire reason to learn it. deck.gl is a WebGL framework from the vis.gl family (started at Uber, now under the OpenJS Foundation) that pushes geospatial data to the GPU as typed arrays and draws it as layers over any basemap. It has 14,524 stars, an MIT license, and it runs in the visitor's browser, which means the self-hosting question is not "where do I run deck.gl" but "where do the tiles and the data come from". Get those two things onto your own servers and you have a Mapbox-free analytics map with no per-load billing.
What you host and what you do not
deck.gl is a JavaScript library; nothing of it runs server-side. The pieces a self-hoster stands up are the basemap tiles, the data files or API the layers fetch, and a web server for the page. For tiles, MapLibre GL JS is the renderer deck.gl pairs with through the @deck.gl/mapbox package, and the tiles themselves come from either a PMTiles archive served as a static file via Protomaps or a running TileServer GL fed by OpenMapTiles data. A Protomaps planet file is around 100 GB; a single country is a few gigabytes and serves from any object store with HTTP range requests. The maps category covers that side in more depth.
The five layers that cover most work
ScatterplotLayer draws points with per-point radius and colour and is the workhorse for anything under about ten million rows. HexagonLayer and GridLayer aggregate points into bins on the GPU, which is how you turn raw sensor pings into a density map without a backend query. ArcLayer draws origin-to-destination curves and is the layer people recognise from flight maps. GeoJsonLayer renders polygons and lines from a GeoJSON feed, and MVTLayer from @deck.gl/geo-layers streams vector tiles so a large polygon dataset never loads at once. A minimal page with MapLibre underneath:
import { MapboxOverlay } from "@deck.gl/mapbox";
import { ScatterplotLayer } from "@deck.gl/layers";
import maplibregl from "maplibre-gl";
const map = new maplibregl.Map({
container: "map",
style: "https://tiles.example.com/styles/light/style.json",
center: [-0.12, 51.5], zoom: 10
});
map.addControl(new MapboxOverlay({
layers: [new ScatterplotLayer({
id: "pings",
data: "https://data.example.com/pings.json",
getPosition: d => [d.lon, d.lat],
getFillColor: [200, 30, 30],
getRadius: 20
})]
}));
Despite the package name, MapboxOverlay works with MapLibre; it predates the fork and was never renamed.
Data format decides whether "millions" is true
The performance claim holds when the data arrives as binary. Feed a layer an array of JavaScript objects and the browser spends its time parsing JSON and building typed arrays; feed it Apache Arrow or a flat Float32Array via the data prop's binary attributes and the GPU upload is close to instant. The companion loaders.gl library parses CSV, Arrow, Parquet, and GeoJSON into that shape. On the server side this means exporting your data as Arrow or as a pre-binned tileset rather than serving a 300 MB GeoJSON, and it means a static file on object storage is usually a better "API" than a live database endpoint.
The learning curve is real
deck.gl assumes you are comfortable with accessor functions, immutable layer updates, and a mental model of what lives on the GPU. Debugging a layer that renders nothing is a matter of checking coordinate order (longitude first), colour arrays (0 to 255, not 0 to 1), and whether the data promise resolved. The React bindings in @deck.gl/react are first-class and are how most production apps use it; plain JavaScript works but the documentation leans React. If what you want is an interactive explorer without writing code, Kepler.gl is built on deck.gl and lets you drop a CSV onto a map with filters and styling in a UI, and it can also be self-hosted.
What I'd do
Protomaps PMTiles for the country you care about on object storage, MapLibre for the basemap, deck.gl through MapboxOverlay for the data layers, data exported nightly as Arrow files next to the tiles. That is a static site plus an object bucket, no map server process to babysit, and it renders datasets that would make a hosted Mapbox bill uncomfortable. Start with Kepler.gl to explore the data and find the layers you want, then write the deck.gl page once you know.
Compare deck.gl
3 head-to-head comparisons.
Similar maps & gis apps
Leaflet
Maps & GISLightweight JavaScript library for interactive maps
Replaces Google Maps JavaScript API
QGIS
Maps & GISFree and open-source geographic information system
Replaces ArcGIS
OpenLayers
Maps & GISHigh-performance library for all kinds of web maps
Replaces Google Maps JavaScript API
kepler.gl
Maps & GISOpen-source geospatial data visualization tool
Replaces Tableau, ArcGIS
MapLibre GL JS
Maps & GISOpen-source interactive vector map library for the web
Replaces Mapbox GL JS, Google Maps JavaScript API
Dawarich
Maps & GISSelf-hosted location history tracker and visualizer
Replaces Google Maps Timeline