Infryne TechWorks logo
INFRYNE TechWorks
◈ Frontend GIS · 60 FPS Performance · Large Datasets

MapLibre GL JS: Performance Guide for Large Datasets

How to render 100,000+ geometries at silky-smooth 60 FPS without freezing the browser thread. Practical patterns for vector tiles, PMTiles, WebGL clustering, and feature-state memory tuning.

Talha WaheedCo-Founder & Head of Engineering15 min read
MapLibre GL JS WebGL map tile grid with vector layers composited on the GPU
← Back to Blog
Quick Answer: Rendering Large Datasets at 60 FPS
TL;DR Performance Architecture

To render large datasets (50,000 to 1,000,000+ features) smoothly at 60 FPS in MapLibre GL JS without freezing the UI thread or exhausting device memory:

01. Stream Vector Tiles / PMTiles

Never pass massive raw GeoJSON to the main thread. Pre-tile geometries into vector tiles (.mvt) or single-file PMTiles so geometry parsing and vertex clipping run in background Web Workers with HTTP range requests.

02. Use `feature-state` for Interactions

Never call map.getSource().setData() to highlight hovered or selected features. Use map.setFeatureState() to update GPU shader attributes in O(1) time without rebuilding geometry buffers.

03. Enable Worker-Side Clustering

For dynamic point datasets under 100k, configure cluster: true with clusterRadius: 50 so Supercluster simplifies point densities on the worker thread before GPU upload.

04. Batch Layers with Expressions

Collapse categorized styling into a single layer driven by data expressions (['match']) rather than 20 individual layers that trigger redundant WebGL draw calls and context state switches.

Dataset ScaleRecommended FormatRendering PipelineTarget Performance
< 5,000 pointsRaw GeoJSONDirect WebGL vertex buffer60 FPS
5k – 100k pointsClustered GeoJSON (cluster: true)Worker-threaded Supercluster60 FPS
50k – 1M+ featuresVector Tiles / PMTilesProtobuf worker decode + GPU VBOs60 FPS (<50ms tiles)
1M+ features / LiDARGeoParquet / FlatGeobuf + Deck.glHardware-instanced WebGL shaders60 FPS with zero lag
See these optimizations running live in our free GeoEditor Web GIS or explore our Web GIS Development Services.

What Is MapLibre GL JS?

MapLibre GL JS is an open-source TypeScript library that renders interactive vector maps directly in the browser using WebGL. Its official documentation covers the renderer, sources, controls, events, and required CSS stylesheets.

MapLibre treats the map as a layered scene rendered with WebGL. Performance depends on the style, source data, viewport, browser, and device, so production tuning should be based on measurements from the actual application.

Why Teams Choose MapLibre

MapLibre is fully open source under the BSD license, GPU-accelerated, supports 3D terrain and vector styling, and pairs effortlessly with self-hosted PMTiles and Martin vector tile services.

MapLibre vs. Mapbox GL JS: Architecture, Licensing & Cost Comparison

When engineering modern web mapping stacks, understanding MapLibre vs Mapbox is the most impactful architectural decision. MapLibre GL JS originated as an open-source fork of Mapbox GL JS v1 after Mapbox shifted to a closed-source, proprietary license with v2. Today, MapLibre is governed independently under the Linux Foundation, backed by AWS, Meta, Microsoft, and Uber, and delivers GPU-accelerated WebGL performance without commercial per-tile API metering.

Comparison DimensionMapLibre GL JSMapbox GL JS (v2/v3)
License & GovernanceBSD 3-Clause (Linux Foundation)Proprietary Single-Vendor
Tile / Map Load Cost$0.00 (Self-hosted PMTiles or Open Basemaps)$0.50–$5.00+ per 1k map loads
Offline & PMTilesNative protocol support via pmtilesRequires custom adapters / hacks
Data Privacy & TelemetryZero phone-home telemetryIntegrated tracking telemetry SDK
WebGL & 3D TerrainGPU-accelerated WebGL2, 3D terrain, globe viewGPU-accelerated WebGL2, 3D terrain, globe view
Backend InteroperabilityMartin (Rust), PostGIS, S3, Cloudflare R2Tightly coupled to Mapbox Studio & APIs

For high-traffic enterprise applications handling millions of spatial queries, migrating from Mapbox to MapLibre GL JS eliminates thousands of dollars in monthly tile costs while guaranteeing complete data sovereignty and vendor independence.

The WebGL Rendering Pipeline

Understanding MapLibre's internal architecture unlocks the ability to write truly performant maps. Every tile load travels through four distinct stages:

01. Fetch & Decode

Vector tiles (.pbf / MVT) are fetched over HTTP and decoded on a Web Worker thread, keeping the main UI thread buttery smooth.

02. Bucket Compilation

Features are sorted into render buckets per layer type, pre-computing vertex buffers and collision spatial indexes.

03. GPU Upload

Compiled geometry buffers are transferred to the GPU as WebGL vertex buffer objects (VBOs) with sprite atlases.

04. Per-Frame Render

The renderer iterates styled layers and issues efficient GPU draw calls at up to 60–120 fps.

Four-stage MapLibre GL JS WebGL rendering pipeline

Next.js Setup

MapLibre GL JS requires browser APIs and cannot run during server-side rendering. In Next.js, initialize the map inside a useEffect hook after the component mounts.

'use client';
import { useEffect, useRef } from 'react';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { Protocol } from 'pmtiles';

export default function MapLibreMap({ center = [77.209, 28.6139], zoom = 11 }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<maplibregl.Map | null>(null);

  useEffect(() => {
    const protocol = new Protocol();
    maplibregl.addProtocol('pmtiles', protocol.tile);

    if (containerRef.current) {
      mapRef.current = new maplibregl.Map({
        container: containerRef.current,
        style: 'https://demotiles.maplibre.org/style.json',
        center,
        zoom,
      });
    }

    return () => {
      mapRef.current?.remove();
      maplibregl.removeProtocol('pmtiles');
    };
  }, []);

  return <div ref={containerRef} className="h-[500px] w-full rounded-xl" />;
}

PMTiles Integration

PMTiles is a single-file tile archive that can be read directly from object storage via HTTP Range Requests. Protomaps documents MapLibre integration with the custom pmtiles:// protocol scheme.

// Load custom PMTiles directly from Cloudflare R2
map.addSource('parcels-source', {
  type: 'vector',
  url: 'pmtiles://https://data.infrynetechworks.com/parcels.pmtiles',
});

map.addLayer({
  id: 'parcels-layer',
  type: 'fill',
  source: 'parcels-source',
  'source-layer': 'parcels',
  paint: {
    'fill-color': '#06b6d4',
    'fill-opacity': 0.6,
  },
});

Layer System & Style Specification

The MapLibre Style Specification defines the JSON schema for sources, layers, sprites, and fonts drawn onto the WebGL canvas.

MapLibre GL JS style layer stack

Custom WebGL Layers

For custom GLSL shaders, particle simulations, or radar sweeps, MapLibre exposes a custom style-layer interface. When visualizing massive datasets (hundreds of thousands of points or animated vehicle trajectories) that push beyond standard style layers, pair MapLibre with our GPU-accelerated Deck.gl Development Services to sustain a locked 60 FPS.

const customLayer = {
  id: 'custom-gl-glow',
  type: 'custom',
  renderingMode: '2d',
  onAdd(map, gl) {
    // Compile shaders and initialize GL buffers
  },
  render(gl, matrix) {
    // Execute custom WebGL draw calls
  }
};
map.addLayer(customLayer);

3D Terrain & Raster DEM Decoding Physics

MapLibre GL JS natively supports true 3D digital elevation models (DEM) via WebGL vertex mesh extrusion. Elevation is encoded inside 24-bit RGB channels of standard raster tiles using one of two standard color-encoding schemes:

Mapbox Terrain-RGB Encoding
elevation = -10000 + ((R × 65536 + G × 256 + B) × 0.1)

Precision: 0.1 meters. Maximum elevation range: -10,000 m to +1.6 million meters. Supported natively with encoding: "mapbox".

Mapzen Terrarium Encoding
elevation = (R × 256 + G + B / 256) - 32768

Precision: 1/256 meter. Maximum range: -32,768 m to +32,768 m. Supported with encoding: "terrarium", ideal for open AWS Terrain tiles.

// Configure MapLibre 3D Terrain with elevation exaggerator
map.addSource('terrain-source', {
  type: 'raster-dem',
  url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
  tileSize: 256,
  encoding: 'terrarium'  // or 'mapbox'
});

map.setTerrain({
  source: 'terrain-source',
  exaggeration: 1.5      // Vertical elevation scale factor
});

Feature State for High-Performance Hover & Selection

MapLibre's setFeatureState() updates feature properties in O(1) time without rebuilding vertex buffers or re-fetching tiles.

map.on('mousemove', 'parcels-layer', (e) => {
  if (e.features?.length) {
    map.setFeatureState(
      { source: 'parcels-source', sourceLayer: 'parcels', id: e.features[0].id },
      { hover: true }
    );
  }
});

Clustering & Performance Optimization

Rendering 100,000+ unclustered GeoJSON points kills framerates because each point requires a GPU vertex transformation and occlusion query. Enable Web Worker-accelerated Supercluster clustering directly on the source:

map.addSource('fleet-telemetry', {
  type: 'geojson',
  data: 'https://data.infrynetechworks.com/vehicles.geojson',
  cluster: true,
  clusterMaxZoom: 14, // Max zoom to cluster points on
  clusterRadius: 50,  // Radius of each cluster in screen pixels
});
TechniqueImpactConfiguration
Set maxzoom on sourcesPrevents unnecessary higher-zoom tile requestsmaxzoom: 14 on source; MapLibre overzooms
Use promoteIdEnables O(1) feature-state stylingpromoteId: { layer: "id" }
Supercluster on WorkerMaintains 60 FPS across 100k+ point datasetscluster: true, clusterRadius: 50
Minimize layer countReduces GPU state switches per frameCombine line layers with filter expressions

Connecting to Martin Tile Server

For dynamic PostGIS data, point MapLibre at Martin endpoints. Martin auto-discovers table geometry columns and returns standard TileJSON. To explore complete serverless vector tile pipelines and cost comparisons, read our guide on Cloud-Native Web Mapping Architectures.

map.addSource('live-sensors', {
  type: 'vector',
  url: 'https://tiles.infrynetechworks.com/sensors', // Martin TileJSON
});

Building a Mapping Application?

High-Performance WebGL Map Engineering

Infryne TechWorks builds production MapLibre GL JS frontends backed by Martin and PMTiles — from interactive geospatial dashboards to real-time asset tracking.

Primary Sources & Datasets

Frequently Asked Questions (MapLibre vs Mapbox)

What is the difference between MapLibre and Mapbox?
MapLibre GL JS is an open-source, community-governed WebGL mapping library under the BSD license, created when Mapbox GL JS closed its source code with version 2. MapLibre has zero per-tile API costs, no tracking telemetry, and native PMTiles and Martin vector tile integration.
Is MapLibre GL JS free for commercial use?
Yes. Under the BSD 3-Clause license, you can freely use, modify, and distribute MapLibre in commercial applications, SaaS products, and government platforms without royalty fees or licensing costs.
Can MapLibre render vector tiles without a commercial tile server?
Yes. By pairing MapLibre GL JS with single-file PMTiles stored on low-cost object storage (such as AWS S3 or Cloudflare R2) or lightweight open-source tile servers like Martin (written in Rust), you can serve planetary vector maps at virtually zero hosting cost.

Continue Reading

More engineering research from Infryne TechWorks

Remote Sensing
Wildfire Burn Scar Mapping with Sentinel-2 & Landsat

Wildfire burn scar mapping using Sentinel-2 and Landsat 8/9 — NBR, BAIS2, RBR spectral indices, NASA FIRMS active fire integration, and the Infryne TechWorks satellite analytics platform.

18 min read
Urban Heat
Heat Is Not Distributed Fairly: Mapping Thermal Inequality in Karachi

A 10-year Landsat archive study overlaying land surface temperature with census wards, income proxies, and tree canopy to map spatial heat burden in Karachi.

24 min read
Remote Sensing
From Raw Satellite Pixels to a Working NDVI Alert Pipeline

A production walkthrough of Sentinel-2 L2A, cloud masking, median composites, spatial validation, CNN inference, and field-ready crop stress alerts.

22 min read
GeoAI
Spatial Data Leakage in Machine Learning: How to Fix It

Random train/test splits can inflate GeoAI accuracy. Learn how spatial autocorrelation causes leakage and how to validate properly.

20 min read
Cloud Engineering
Scaling Geospatial Pipelines: From 10 Files to 10,000 in AWS Batch

A production field guide to AWS Batch array jobs, container memory failures, IAM roles, S3 request smoothing, and scaling imagery processing to 10,000 tiles.

9 min read
GIS Engineering
Cloud-Native Web Mapping Architecture: A Practical Guide

How to design scalable web maps with PostGIS, vector tiles, PMTiles, and MapLibre. Architecture patterns, trade-offs, and costs.

18 min read
GeoAI
Scaling Spatial Pipelines: Why Your Location Queries Are Crashing

A field guide to PostGIS storefront architecture, ST_DWithin indexing, and the decisions that pull spatial systems back from the edge.

8 min read