All skills
mapbox avatar

/mapbox-google-maps-migration

@65bab68 official
by mapboxmapbox/mapbox-agent-skills80 stars
17

Migration guide for developers moving from Google Maps Platform to Mapbox GL JS, covering API equivalents, pattern translations, and key differences

Use this Skill: https://skilld.dev/gh/mapbox/mapbox-agent-skills/mapbox-google-maps-migration

This session only. Nothing lands on disk.

AGENTS.md

≈2.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Google Maps to Mapbox GL JS Migration Guide

Quick reference for migrating from Google Maps Platform to Mapbox GL JS with API equivalents and patterns.

Critical Differences

Aspect Google Maps Mapbox GL JS
Coordinates {lat, lng} objects [lng, lat] arrays
Philosophy Imperative (objects) Declarative (data-driven)
Rendering DOM elements WebGL (much faster)
Performance Slow with 500+ markers Fast with 10,000+ points
Initialization new google.maps.Map() new mapboxgl.Map()

Quick Migration Checklist

✅ Install mapbox-gl package ✅ Get Mapbox access token ✅ Swap coordinate order (lat,lng → lng,lat) ✅ Replace Google Maps API with Mapbox equivalents ✅ Use Symbol layers for 100+ markers (not HTML markers) ✅ Add clustering for 500+ points ✅ Update geocoding to Mapbox Geocoding API ✅ Test all functionality

API Equivalents

Map Initialization

// Google Maps
const map = new google.maps.Map(document.getElementById('map'), {
  center: { lat: 37.7749, lng: -122.4194 },
  zoom: 12
});

// Mapbox GL JS
mapboxgl.accessToken = 'pk.your_token';
const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12',
  center: [-122.4194, 37.7749], // Note: [lng, lat]
  zoom: 12
});

Individual Markers (< 50 points)

// Google Maps
const marker = new google.maps.Marker({
  position: { lat: 37.7749, lng: -122.4194 },
  map: map
});

// Mapbox (equivalent approach)
const marker = new mapboxgl.Marker().setLngLat([-122.4194, 37.7749]).addTo(map);

Many Markers (100+ points) - Performance Critical

// ❌ Google Maps: DOM-based (slow with 500+ markers)
locations.forEach((loc) => {
  new google.maps.Marker({
    position: { lat: loc.lat, lng: loc.lng },
    map: map
  });
});

// ✅ Mapbox: WebGL-based (fast with 10,000+ points)
map.addSource('points', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: locations.map((loc) => ({
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [loc.lng, loc.lat] }
    }))
  }
});

map.addLayer({
  id: 'points',
  type: 'symbol',
  source: 'points',
  layout: {
    'icon-image': 'marker-15'
  }
});

Performance Note: Google Maps renders ALL markers as DOM elements (even with Data Layer). Mapbox uses WebGL for Symbol/Circle layers = 10-100x faster for large datasets.

Clustering (500+ points)

// Google Maps (requires MarkerClusterer library)
import MarkerClusterer from '@googlemaps/markerclustererplus';
const clusterer = new MarkerClusterer(map, markers);

// Mapbox (built-in)
map.addSource('points', {
  type: 'geojson',
  data: geojson,
  cluster: true,
  clusterRadius: 50
});

Info Windows / Popups

// Google Maps
const infowindow = new google.maps.InfoWindow({
  content: '<h3>Title</h3>'
});
infowindow.open(map, marker);

// Mapbox
const popup = new mapboxgl.Popup().setHTML('<h3>Title</h3>').setLngLat([-122.4194, 37.7749]).addTo(map);

// Or attach to marker
marker.setPopup(popup);

Events

// Google Maps
marker.addListener('click', () => {
  /* ... */
});
map.addListener('click', (e) => {
  const lat = e.latLng.lat();
  const lng = e.latLng.lng();
});

// Mapbox
marker.on('click', () => {
  /* ... */
});
map.on('click', (e) => {
  const [lng, lat] = [e.lngLat.lng, e.lngLat.lat];
});

Geocoding

// Google Maps
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: '1600 Amphitheatre Parkway' }, (results) => {
  map.setCenter(results[0].geometry.location);
});

// Mapbox
fetch(
  `https://api.mapbox.com/search/geocode/v6/forward?q=1600+Amphitheatre+Parkway&access_token=${mapboxgl.accessToken}`
)
  .then((r) => r.json())
  .then((data) => {
    const [lng, lat] = data.features[0].geometry.coordinates;
    map.setCenter([lng, lat]);
  });

Directions

// Google Maps
const directionsService = new google.maps.DirectionsService();
directionsService.route(
  {
    origin: 'San Francisco',
    destination: 'Los Angeles',
    travelMode: 'DRIVING'
  },
  (result) => {
    /* ... */
  }
);

// Mapbox
fetch(
  `https://api.mapbox.com/directions/v5/mapbox/driving/-122.4194,37.7749;-118.2437,34.0522?access_token=${mapboxgl.accessToken}`
)
  .then((r) => r.json())
  .then((data) => {
    const route = data.routes[0].geometry;
    // Display route on map
  });

Polygons/Shapes

// Google Maps
const polygon = new google.maps.Polygon({
  paths: coordinates,
  map: map
});

// Mapbox
map.addSource('polygon', {
  type: 'geojson',
  data: {
    type: 'Feature',
    geometry: {
      type: 'Polygon',
      coordinates: [coordinates] // Note: Array of arrays
    }
  }
});

map.addLayer({
  id: 'polygon',
  type: 'fill',
  source: 'polygon',
  paint: {
    'fill-color': '#088',
    'fill-opacity': 0.5
  }
});

Coordinate Order - CRITICAL

Most common migration bug:

// ❌ Google Maps order (lat, lng)
{ lat: 37.7749, lng: -122.4194 }

// ✅ Mapbox order (lng, lat)
[-122.4194, 37.7749]

// Remember: Mapbox follows GeoJSON standard (longitude first)

Performance Advantages

Mapbox is significantly faster for:

  1. Large datasets: 500+ markers (Symbol layers vs DOM markers)
  2. Data visualization: Choropleth, heatmaps (WebGL rendering)
  3. Custom styling: Full control over every visual element
  4. Vector tiles: Efficient data loading and rendering

When Mapbox wins:

  • Rendering 10,000+ points smoothly
  • Custom map styles (not just pins on a map)
  • Data-driven visualizations
  • Performance-critical applications

When Google Maps might be better:

  • Need Street View
  • Heavy Google Workspace integration
  • Places API is critical
  • Team has deep Google Maps expertise

Styling Comparison

// Google Maps (limited styling)
const styledMapType = new google.maps.StyledMapType([{ elementType: 'geometry', stylers: [{ color: '#242f3e' }] }]);

// Mapbox (full control)
map.setStyle('mapbox://styles/mapbox/dark-v11');
// Or create custom styles in Mapbox Studio

Mapbox Styles:

  • streets-v12 - Standard streets
  • outdoors-v12 - Hiking/outdoor
  • light-v11 / dark-v11 - Minimal
  • satellite-v9 / satellite-streets-v12 - Imagery
  • Custom styles via Mapbox Studio

Common Migration Patterns

Store Locator

Google Maps: Create marker for each store, add click listeners, show info windows Mapbox: Use Symbol layer + click events + popups (much faster for 100+ stores)

Route Display

Google Maps: DirectionsRenderer Mapbox: Fetch route from Directions API, add as Line layer

Heatmaps

Google Maps: HeatmapLayer (DOM-based) Mapbox: Heatmap layer (WebGL-based, much faster)

Token & Pricing

Google Maps:

  • Requires API key
  • Pay per map load + API calls
  • Free tier: $200/month credit

Mapbox:

  • Requires access token (pk.* for client-side)
  • Pay per map load + API calls
  • Free tier: 50,000 map loads/month

Token setup:

// Store in environment variables
mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN;

Testing Migration

Checklist:

  1. ✅ Map displays at correct location
  2. ✅ All markers/pins visible
  3. ✅ Click events work
  4. ✅ Popups display correctly
  5. ✅ Geocoding returns results
  6. ✅ Directions routing works
  7. ✅ Performance improved (if using Symbol layers)
  8. ✅ Mobile works (touch events)

Migration Strategy

Phase 1: Setup

  • Install Mapbox GL JS
  • Get access token
  • Create test page

Phase 2: Core Migration

  • Initialize map
  • Swap coordinate order
  • Convert markers (use Symbol layers for 100+)
  • Migrate popups/info windows

Phase 3: Features

  • Geocoding
  • Directions
  • Custom styling
  • Events

Phase 4: Optimization

  • Add clustering (if 500+ points)
  • Implement proper cleanup
  • Test performance
  • Mobile optimization

Quick Wins

Easy migrations (mostly drop-in replacements):

  • Basic map initialization
  • Individual markers (< 50)
  • Popups
  • Map controls
  • Click events

Requires rethinking (but worth it):

  • Large marker sets → Symbol layers (10-100x faster)
  • Custom styling → Mapbox Studio
  • Heatmaps → Heatmap layers (WebGL)

When NOT to Migrate

Consider staying with Google Maps if:

  • Street View is critical
  • Heavy Places API usage
  • Team has deep Google Maps expertise
  • Already heavily optimized
  • Short-term project

Source: SKILL.md on GitHub

1 warning15d5 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    This skill is a safe and educational migration guide for developers moving from Google Maps to Mapbox GL JS. It provides technical comparisons, API equivalents, and best practices for performance optimization. All external references and code samples target official Mapbox services and reputable open-source libraries.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

  • Runlayer7mo

    2/2 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 65bab68. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 8 hours ago.

Activeupdated 6 months ago
  • mapbox
  • google-maps
  • migration
  • mapping
  • javascript
  • geospatial
  • gl-js
  • web-mapping

README badge

README badge for mapbox/mapbox-agent-skills/mapbox-google-maps-migration

Guides developers migrating from Google Maps Platform to Mapbox GL JS, covering API method equivalents, coordinate order differences, and architectural patterns. Includes reference tables for map methods and events, marker strategies for different data volumes, and gotchas like timing issues and data updates that cause visual flashing.

Generated from the current SKILL.md.

Does Mapbox have a Street View equivalent?
No. Street View is not available in Mapbox GL JS, so if Street View is critical to your application, you should stay with Google Maps.
What's the coordinate order difference between Google Maps and Mapbox?
Google Maps uses {lat, lng} while Mapbox uses [lng, lat] (reversed). This applies to all methods: map.setCenter(), marker.setLngLat(), fitBounds(), etc.
How do I handle large numbers of markers in Mapbox?
For 100+ points, use data-driven layers (GeoJSON sources + circle/symbol layers) instead of individual marker objects. Mapbox renders these with WebGL, making them much faster than DOM-based markers for 1,000-10,000+ points.
How do I update marker data without causing a visual flash?
Call map.getSource('source-id').setData(newGeoJSON) to update data in place, or use map.setFilter() to filter existing data on the GPU. Never remove and re-add layers to update data, as this reinitializes WebGL resources and causes a visible flash.
What authentication method does Mapbox use?
Mapbox uses access tokens set in code (mapboxgl.accessToken = 'YOUR_TOKEN'), whereas Google Maps uses API keys in the script tag.

Generated from the current SKILL.md. These answers refresh after source changes.