Add an uploaded vector tileset in Leaflet
Copy JavaScript and React examples for loading an uploaded vector tileset from Mappinest TileJSON in Leaflet.
Overview
This guide shows how to add an uploaded vector tileset in Leaflet with the same MapLibre renderer used for the Mappinest map style.
If your tileset starts as an MBTiles or PMTiles file, upload it through the console first. See Upload Data for the full upload workflow, then copy the tileset Id from the Tileset ID column and get an API key from API Keys & Access.
The example mounts MapLibre inside Leaflet with @maplibre/maplibre-gl-leaflet, then adds mappinest.COUNTIES as a MapLibre vector source through the tileset TileJSON URL. Use the Leaflet.VectorGrid guide when you need Leaflet-native layer events, popups, or plugin workflows for the uploaded vector tileset.
For production, replace mappinest.COUNTIES with your own tileset Id from the Tileset ID column in the console. Use the source layer returned by the TileJSON vector_layers array when you add the map layer.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mappinest vector TileJSON with Leaflet and MapLibre</title>
<link href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" rel="stylesheet" />
<link href="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.css" rel="stylesheet" />
<style>
body { margin: 0; }
#map { height: 100vh; width: 100vw; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.1.3/leaflet-maplibre-gl.js"></script>
<script>
const apiKey = 'YOUR_MAPPINEST_KEY';
const map = L.map('map').setView([39.8283, -98.5795], 4);
// Set this to the TileJSON vector_layers[].id value for the layer you want to draw.
const sourceLayer = 'COUNTIES';
const glLayer = L.maplibreGL({
style: `https://api.mappinest.com/v1/maps/light/style.json?key=${apiKey}`,
interactive: false
}).addTo(map);
const glMap = glLayer.getMaplibreMap();
function addCountriesLayer() {
if (glMap.getSource('mappinest-counties')) return;
glMap.addSource('mappinest-counties', {
type: 'vector',
url: `https://api.mappinest.com/v1/tiles/mappinest.COUNTIES.json?key=${apiKey}`
});
glMap.addLayer({
id: 'mappinest-counties-fill',
type: 'fill',
source: 'mappinest-counties',
'source-layer': sourceLayer,
paint: {
'fill-color': '#2563eb',
'fill-opacity': 0.28
}
});
glMap.addLayer({
id: 'mappinest-counties-outline',
type: 'line',
source: 'mappinest-counties',
'source-layer': sourceLayer,
paint: {
'line-color': '#1d4ed8',
'line-width': 1
}
});
}
if (glMap.isStyleLoaded()) {
addCountriesLayer();
} else {
glMap.once('load', addCountriesLayer);
}
</script>
</body>
</html>import { useEffect, useRef } from 'react';
import L from 'leaflet';
import '@maplibre/maplibre-gl-leaflet';
import 'leaflet/dist/leaflet.css';
import 'maplibre-gl/dist/maplibre-gl.css';
const apiKey = 'YOUR_MAPPINEST_KEY';
export default function MappinestLeafletVectorTilesMap() {
const containerRef = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<L.Map | null>(null);
useEffect(() => {
if (!containerRef.current || mapRef.current) return;
const map = L.map(containerRef.current).setView([39.8283, -98.5795], 4);
mapRef.current = map;
// Set this to the TileJSON vector_layers[].id value for the layer you want to draw.
const sourceLayer = 'COUNTIES';
const glLayer = (L as any).maplibreGL({
style: `https://api.mappinest.com/v1/maps/light/style.json?key=${apiKey}`,
interactive: false
}).addTo(map);
const glMap = glLayer.getMaplibreMap();
function addCountriesLayer() {
if (glMap.getSource('mappinest-counties')) return;
glMap.addSource('mappinest-counties', {
type: 'vector',
url: `https://api.mappinest.com/v1/tiles/mappinest.COUNTIES.json?key=${apiKey}`
});
glMap.addLayer({
id: 'mappinest-counties-fill',
type: 'fill',
source: 'mappinest-counties',
'source-layer': sourceLayer,
paint: {
'fill-color': '#2563eb',
'fill-opacity': 0.28
}
});
glMap.addLayer({
id: 'mappinest-counties-outline',
type: 'line',
source: 'mappinest-counties',
'source-layer': sourceLayer,
paint: {
'line-color': '#1d4ed8',
'line-width': 1
}
});
}
if (glMap.isStyleLoaded()) {
addCountriesLayer();
} else {
glMap.once('load', addCountriesLayer);
}
return () => {
map.remove();
mapRef.current = null;
};
}, []);
return <div ref={containerRef} style={{ height: 420, width: '100%' }} />;
}URL patterns used in this example
The bold parameters are the values you replace. Prefer TileJSON as the integration request so the tile template, bounds, zoom range, and vector layer metadata stay behind one URL.
Get your free API key in API Keys & Access, then replace YOUR_KEY in the example.
Common errors
What to read next
Last updated: August 25, 2026