MapSnippets logoMapSnippets logo

Route from A to B

Calculate and display driving routes Each library has its own approach: here's how they compare.

Quick Recommendations

Leaflet — The right choice when you want a ready-made routing UI with turn-by-turn instructions via the Leaflet Routing Machine plugin.

MapLibre GL JS — Makes the most sense when you need full control over route line styling with paint expressions and want to integrate routing into a data-driven map.

OpenLayers — A strong fit when routing must integrate with existing OGC/vector feature workflows and you need precise geometry operations on the route.

At a Glance

LeafletMapLibreOpenLayers
Coordinates[lat, lng][lng, lat]fromLonLat([lng, lat])
RenderingDOM + Canvas (2D)WebGL (GPU, 60fps)Canvas + WebGL
Bundle size~42 KB gzipped~250 KB gzipped~290 KB gzipped (tree-shakeable)
Learning curveEasiest (simple API, great tutorials)Moderate (source/layer model, expressions)Steepest (projections, OGC standards, verbose API)
3D supportNo native 3D (2D only)Full: terrain, fill-extrusion, globe, skyLimited: WebGL layers, no native globe
Code lines132327

Implementation Details

LeafletMapLibreOpenLayers
Routing EngineOSRM (external): MapTiler has no routing APIOSRM (external): route rendered as GeoJSON line layerOSRM (external): route as vector feature

Code Snippets

Click a library to expand its code. Each snippet shows only the core logic: the scaffold handles HTML boilerplate.

Leaflet13 linesShow code
arrow_forwardFull example
const map = L.map('map').setView([48.86, 2.35], 12);
L.tileLayer('https://api.maptiler.com/maps/streets-v4/256/{z}/{x}/{y}.png?key=YOUR_MAPTILER_KEY', {
  tileSize: 256,
  attribution: '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>'
}).addTo(map);
L.marker([48.8566, 2.3522]).addTo(map).bindPopup('Start: Paris Center');
L.marker([48.8738, 2.2950]).addTo(map).bindPopup('End: Arc de Triomphe');
fetch('https://router.project-osrm.org/route/v1/driving/2.3522,48.8566;2.2950,48.8738?overview=full&geometries=geojson')
  .then(r => r.json())
  .then(data => {
    const coords = data.routes[0].geometry.coordinates.map(c => [c[1], c[0]]);
    L.polyline(coords, { color: '#2196F3', weight: 5, opacity: 0.8 }).addTo(map);
  });
MapLibre GL JS23 linesShow code
arrow_forwardFull example
const map = new maplibregl.Map({
  container: 'map',
  style: 'https://api.maptiler.com/maps/streets-v4/style.json?key=YOUR_MAPTILER_KEY',
  center: [2.35, 48.86],
  zoom: 12
});
map.addControl(new maplibregl.NavigationControl());
const start = [2.3364, 48.8606], end = [2.2945, 48.8584];
map.on('load', async () => {
  const url = `https://router.project-osrm.org/route/v1/driving/${start[0]},${start[1]};${end[0]},${end[1]}?overview=full&geometries=geojson`;
  const res = await fetch(url);
  const data = await res.json();
  if (!data.routes.length) return;
  map.addSource('route', { type: 'geojson', data: { type: 'Feature', geometry: data.routes[0].geometry } });
  map.addLayer({ id: 'route-line', type: 'line', source: 'route',
    layout: { 'line-join': 'round', 'line-cap': 'round' },
    paint: { 'line-color': '#2196F3', 'line-width': 5 } });
  new maplibregl.Marker({ color: '#4CAF50' }).setLngLat(start).setPopup(new maplibregl.Popup().setText('Start: Louvre')).addTo(map);
  new maplibregl.Marker({ color: '#F44336' }).setLngLat(end).setPopup(new maplibregl.Popup().setText('End: Eiffel Tower')).addTo(map);
  const coords = data.routes[0].geometry.coordinates;
  const bounds = coords.reduce((b, c) => b.extend(c), new maplibregl.LngLatBounds(coords[0], coords[0]));
  map.fitBounds(bounds, { padding: 60 });
});
OpenLayers27 linesShow code
arrow_forwardFull example
var startCoord = [2.3522, 48.8566];
var endCoord = [2.2945, 48.8584];
var markerLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: [
      new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat(startCoord)) }),
      new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat(endCoord)) })
    ]
  }),
  style: new ol.style.Style({ image: new ol.style.Circle({ radius: 8, fill: new ol.style.Fill({ color: '#e63946' }), stroke: new ol.style.Stroke({ color: '#fff', width: 2 }) }) })
});
var routeLayer = new ol.layer.Vector({ source: new ol.source.Vector(), style: new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#457b9d', width: 5 }) }) });
var map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({ source: new ol.source.XYZ({ url: 'https://api.maptiler.com/maps/streets-v4/256/{z}/{x}/{y}.png?key=YOUR_MAPTILER_KEY', attributions: '&copy; <a href="https://www.maptiler.com/copyright/">MapTiler</a>' }) }),
    routeLayer, markerLayer
  ],
  view: new ol.View({ center: ol.proj.fromLonLat([2.32, 48.858]), zoom: 14 })
});
fetch('https://router.project-osrm.org/route/v1/driving/' + startCoord[0] + ',' + startCoord[1] + ';' + endCoord[0] + ',' + endCoord[1] + '?overview=full&geometries=geojson')
  .then(function(r) { return r.json(); })
  .then(function(data) {
    var coords = data.routes[0].geometry;
    var feature = new ol.format.GeoJSON().readFeature({ type: 'Feature', geometry: coords }, { featureProjection: 'EPSG:3857' });
    routeLayer.getSource().addFeature(feature);
  });

Things to Know

Implementation-specific details that matter for route from a to b.

Leaflet

Leaflet Routing Machine handles OSRM API calls and renders a turn-by-turn instruction panel automatically; the route line uses L.polyline.

MapLibre GL JS

You must handle the OSRM fetch manually and add the decoded route geometry as a GeoJSON line layer; no built-in routing UI.

OpenLayers

OSRM response is decoded and rendered as an ol.Feature with LineString geometry; no built-in routing panel.

Which Library to Use?

auto_awesome

Build Maps with AI

Generate code like these examples using mapping library skills in your IDE.