Google has been tightening its Maps Platform for years, but the May 2026 deprecation wave is the most disruptive one yet. Four widely used features are being removed from the Maps JavaScript API: the Heatmap Layer, the Drawing Library, DirectionsService, and DistanceMatrixService. If your application relies on any of them, you have weeks to migrate before your code stops working.
This is not a soft deprecation where the old endpoints linger for years. Google has set hard removal dates, and the developer console is already surfacing warnings. This guide covers exactly what is changing, why Google is doing it, and how to migrate each service with working code examples. If you need a drop-in replacement, we will show you how MapAtlas APIs map to each deprecated Google service.
What Is Being Deprecated and When
Here is the complete timeline of affected services:
| Service | Deprecated | Removal Date | Replacement (Google) |
|---|---|---|---|
| Heatmap Layer (Maps JS API) | August 2025 | May 2026 | Maps Datasets API + deck.gl |
| Drawing Library (Maps JS API) | May 2025 | May 2026 | Extended Component Library |
| DirectionsService (Maps JS API) | February 25, 2026 | May 2026 | Routes API (REST) |
| DistanceMatrixService (Maps JS API) | February 25, 2026 | May 2026 | Routes API (REST) |
The critical detail: Google is not removing routing and distance calculations entirely. It is removing the JavaScript client-side classes that developers have been using for over a decade and forcing migration to the newer Routes API, which is a server-side REST endpoint. This is not a simple version bump. It is an architectural change that moves routing logic from the browser to your backend.
What Breaks
If your codebase contains any of the following, it will fail after the removal date:
// All of these will stop working in May 2026
const directionsService = new google.maps.DirectionsService();
const distanceMatrixService = new google.maps.DistanceMatrixService();
const heatmap = new google.maps.visualization.HeatmapLayer({ data: points });
const drawingManager = new google.maps.drawing.DrawingManager();
After removal, these constructors will throw errors. There is no fallback behavior, no graceful degradation. Your map will load, but any feature that depends on these classes will break completely.
Why Google Is Forcing These Changes
Google's stated rationale is performance and modernization. The Routes API (the replacement for DirectionsService and DistanceMatrixService) supports newer features like eco-friendly routing, two-wheeled vehicle routing, and toll cost estimation that the legacy JavaScript classes cannot accommodate.
The real driver is pricing control. By moving routing to a server-side REST API, Google gains finer-grained billing and usage tracking. The JavaScript DirectionsService allowed client-side batching patterns that were harder for Google to meter accurately. The Routes API ensures every request passes through a metered endpoint.
For the Heatmap Layer and Drawing Library, Google is pushing developers toward its Extended Component Library and third-party visualization tools like deck.gl. This is part of a broader pattern: Google keeps the core map tile rendering in-house and offloads everything else to the ecosystem.
The practical impact for developers is more backend infrastructure, more API keys to manage, and in most cases, higher costs per request on the new pricing tiers.
Migration Checklist
Before writing any migration code, work through this checklist:
1. Audit Your Codebase
Search your codebase for references to the deprecated classes:
# Find all files using deprecated Google Maps services
grep -rn "DirectionsService\|DistanceMatrixService\|HeatmapLayer\|visualization.HeatmapLayer\|drawing.DrawingManager\|DrawingManager" \
--include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" src/
Document every file and component that uses these services. Note whether the calls happen client-side (browser) or in a server-rendered context (Next.js API routes, for example).
2. Identify Your Usage Patterns
For each usage, document:
- Travel modes used (driving, walking, cycling, transit)
- Waypoint support (simple A-to-B, or multi-stop routes)
- Response fields consumed (distance, duration, polyline, steps, fare)
- Volume (requests per day/month, for cost estimation)
- Latency requirements (real-time user-facing, or batch processing)
3. Choose Your Migration Target
You have two options:
Option A: Stay with Google. Migrate from the deprecated JavaScript classes to the new Google Routes API (REST). This requires backend changes, new API key permissions, and updated billing.
Option B: Switch providers. Migrate to a third-party routing API. This is the right time to evaluate alternatives, since you are rewriting the integration code anyway.
4. Set Up a Parallel Environment
Never migrate in-place. Run the old and new implementations side by side for at least two weeks, comparing results for accuracy and latency before cutting over.
5. Update Error Handling
The deprecated services returned errors through callback functions. REST API replacements return HTTP status codes. Your error handling logic needs to change accordingly.
API-by-API Replacement Guide
DirectionsService to MapAtlas Directions API
Before (Google, deprecated):
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin: { lat: 52.52, lng: 13.405 },
destination: { lat: 48.8566, lng: 2.3522 },
travelMode: google.maps.TravelMode.DRIVING,
waypoints: [
{ location: { lat: 50.9375, lng: 6.9603 }, stopover: true }
],
},
(result, status) => {
if (status === "OK") {
const route = result.routes[0];
console.log("Distance:", route.legs[0].distance.text);
console.log("Duration:", route.legs[0].duration.text);
}
}
);
After (MapAtlas Directions API):
const response = await fetch(
"https://api.mapatlas.com/v1/directions?" +
new URLSearchParams({
origin: "52.52,13.405",
destination: "48.8566,2.3522",
waypoints: "50.9375,6.9603",
mode: "driving",
key: process.env.MAPATLAS_API_KEY!,
})
);
const data = await response.json();
if (data.status === "OK") {
const leg = data.routes[0].legs[0];
console.log("Distance:", leg.distance.text);
console.log("Duration:", leg.duration.text);
// Polyline for map rendering
const polyline = data.routes[0].overview_polyline;
}
Key differences:
- REST endpoint instead of a JavaScript class. Calls go from your backend, not the browser.
- Simpler authentication. One API key in the query string or header.
- Same response structure. Routes, legs, distance, duration, and polyline are all present.
DistanceMatrixService to MapAtlas Matrix API
Before (Google, deprecated):
const service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 48.1351, lng: 11.582 },
],
destinations: [
{ lat: 48.8566, lng: 2.3522 },
{ lat: 51.5074, lng: -0.1278 },
],
travelMode: google.maps.TravelMode.DRIVING,
},
(response, status) => {
if (status === "OK") {
response.rows.forEach((row, i) => {
row.elements.forEach((element, j) => {
console.log(`Origin ${i} -> Dest ${j}:`,
element.distance.text, element.duration.text);
});
});
}
}
);
After (MapAtlas Matrix API):
const response = await fetch("https://api.mapatlas.com/v1/matrix", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.MAPATLAS_API_KEY}`,
},
body: JSON.stringify({
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 48.1351, lng: 11.582 },
],
destinations: [
{ lat: 48.8566, lng: 2.3522 },
{ lat: 51.5074, lng: -0.1278 },
],
mode: "driving",
}),
});
const data = await response.json();
data.rows.forEach((row: any, i: number) => {
row.elements.forEach((element: any, j: number) => {
console.log(`Origin ${i} -> Dest ${j}:`,
element.distance.text, element.duration.text);
});
});
The response shape is nearly identical. The main change is moving from a callback-based browser API to a promise-based server API.
Heatmap Layer Replacement
For heatmap visualization, the migration path depends on your requirements:
Option 1: MapLibre GL JS with a heatmap layer (open source)
import maplibregl from "maplibre-gl";
const map = new maplibregl.Map({
container: "map",
style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
center: [13.405, 52.52],
zoom: 10,
});
map.on("load", () => {
map.addSource("heat-data", {
type: "geojson",
data: {
type: "FeatureCollection",
features: heatmapPoints.map((point) => ({
type: "Feature",
geometry: { type: "Point", coordinates: [point.lng, point.lat] },
properties: { weight: point.weight },
})),
},
});
map.addLayer({
id: "heatmap-layer",
type: "heatmap",
source: "heat-data",
paint: {
"heatmap-weight": ["get", "weight"],
"heatmap-intensity": 1,
"heatmap-radius": 20,
"heatmap-opacity": 0.7,
},
});
});
This gives you full control over the heatmap rendering and does not depend on Google's tile servers.
Option 2: deck.gl HeatmapLayer (Google's own recommendation)
import { Deck } from "@deck.gl/core";
import { HeatmapLayer } from "@deck.gl/aggregation-layers";
const heatmapLayer = new HeatmapLayer({
data: heatmapPoints,
getPosition: (d) => [d.lng, d.lat],
getWeight: (d) => d.weight,
radiusPixels: 30,
});
Both options work. MapLibre GL JS integrates cleanly with MapAtlas tile styles, while deck.gl can overlay on any base map.
Cost Comparison: Google Routes API vs. MapAtlas
Migrating to Google's own Routes API is not just a code change. It comes with new pricing:
| Service | Google (legacy, per 1,000) | Google Routes API (per 1,000) | MapAtlas (per 1,000) |
|---|---|---|---|
| Directions (basic) | $5.00 | $5.00 | $1.50 |
| Directions (advanced, waypoints/traffic) | $10.00 | $10.00 | $2.50 |
| Distance Matrix (per element) | $5.00 | $5.00 | $1.00 |
| Distance Matrix (advanced) | $10.00 | $10.00 | $2.00 |
| Geocoding | $5.00 | $5.00 | $1.50 |
At 100,000 routing requests per month:
- Google Routes API: ~$500 - $1,000 (depending on features used)
- MapAtlas Directions API: ~$150 - $250
The savings compound quickly for applications that combine routing with geocoding and distance calculations. A logistics platform processing 500,000 matrix elements per month would pay roughly $2,500 on Google versus $500 on MapAtlas.
For full pricing details, see MapAtlas pricing.
Code Migration Examples: Full Before/After
Here is a complete migration example for a React component that shows driving directions on a map.
Before: Google Maps DirectionsService in React
import { useEffect, useRef } from "react";
function DirectionsMap({ origin, destination }: {
origin: google.maps.LatLngLiteral;
destination: google.maps.LatLngLiteral;
}) {
const mapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const map = new google.maps.Map(mapRef.current!, {
center: origin,
zoom: 7,
});
const directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin,
destination,
travelMode: google.maps.TravelMode.DRIVING,
},
(result, status) => {
if (status === "OK" && result) {
directionsRenderer.setDirections(result);
}
}
);
}, [origin, destination]);
return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}
After: MapAtlas Directions API with MapLibre GL JS
import { useEffect, useRef } from "react";
import maplibregl from "maplibre-gl";
function DirectionsMap({ origin, destination }: {
origin: { lat: number; lng: number };
destination: { lat: number; lng: number };
}) {
const mapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const map = new maplibregl.Map({
container: mapRef.current!,
style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
center: [origin.lng, origin.lat],
zoom: 7,
});
map.on("load", async () => {
// Fetch directions from your backend (or directly if CORS allows)
const res = await fetch(
`/api/directions?` +
new URLSearchParams({
origin: `${origin.lat},${origin.lng}`,
destination: `${destination.lat},${destination.lng}`,
mode: "driving",
})
);
const data = await res.json();
if (data.routes?.[0]) {
const coordinates = data.routes[0].geometry.coordinates;
map.addSource("route", {
type: "geojson",
data: {
type: "Feature",
geometry: { type: "LineString", coordinates },
properties: {},
},
});
map.addLayer({
id: "route-line",
type: "line",
source: "route",
paint: {
"line-color": "#4A90D9",
"line-width": 5,
},
});
// Fit map to route bounds
const bounds = coordinates.reduce(
(b: maplibregl.LngLatBounds, coord: [number, number]) =>
b.extend(coord),
new maplibregl.LngLatBounds(coordinates[0], coordinates[0])
);
map.fitBounds(bounds, { padding: 50 });
}
});
return () => map.remove();
}, [origin, destination]);
return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}
Backend API Route (Next.js)
// app/api/directions/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const origin = searchParams.get("origin");
const destination = searchParams.get("destination");
const mode = searchParams.get("mode") || "driving";
const response = await fetch(
`https://api.mapatlas.com/v1/directions?` +
new URLSearchParams({
origin: origin!,
destination: destination!,
mode,
key: process.env.MAPATLAS_API_KEY!,
})
);
const data = await response.json();
return NextResponse.json(data);
}
This pattern keeps your API key on the server and exposes only the route geometry to the client.
How to Test Your Migration Before the Deadline
Step 1: Run Both APIs in Parallel
For two weeks before cutting over, call both the old Google service and the new replacement for every request. Log both responses and compare:
async function getDirectionsWithComparison(
origin: string,
destination: string
) {
const [googleResult, mapatResult] = await Promise.all([
fetchGoogleDirections(origin, destination),
fetchMapAtlasDirections(origin, destination),
]);
// Compare key metrics
const distanceDelta = Math.abs(
googleResult.distance - mapatResult.distance
);
const durationDelta = Math.abs(
googleResult.duration - mapatResult.duration
);
console.log({
route: `${origin} -> ${destination}`,
googleDistance: googleResult.distance,
mapatDistance: mapatResult.distance,
distanceDeltaPercent: ((distanceDelta / googleResult.distance) * 100).toFixed(1),
googleDuration: googleResult.duration,
mapatDuration: mapatResult.duration,
durationDeltaPercent: ((durationDelta / googleResult.duration) * 100).toFixed(1),
});
// Use MapAtlas result in production, Google as validation
return mapatResult;
}
Step 2: Set Up Feature Flags
Use a feature flag to control which API your application calls. This lets you roll back instantly if you encounter issues:
const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";
const directions = useMapAtlasDirections
? await fetchMapAtlasDirections(origin, destination)
: await fetchGoogleDirections(origin, destination);
Step 3: Monitor Error Rates
After switching, monitor for:
- HTTP 4xx/5xx error rates from the new API
- Latency increases (new provider may have different response times)
- Missing fields in responses that your UI depends on
- Route accuracy for edge cases (ferry routes, toll roads, restricted areas)
Step 4: Load Test Before Go-Live
If your application handles spikes (e.g., a logistics platform during morning dispatch), load test the new API at 2x your peak volume. MapAtlas offers a sandbox environment for load testing without incurring production billing.
Timeline: What to Do This Week
If you have not started migrating, here is the priority order:
- This week: Audit your codebase. Identify every usage of the four deprecated services.
- Week 2: Set up a MapAtlas account and get API keys. The free tier covers 10,000 requests for testing.
- Week 3: Implement the replacement for your most critical service (usually DirectionsService).
- Week 4: Migrate remaining services and run parallel testing.
- Before May deadline: Cut over, remove Google API dependencies, update billing.
The migration is not optional. After May 2026, the deprecated classes will be removed from the Maps JavaScript API, and any code that references them will throw runtime errors. Start now, and you will have time to test properly. Wait until the last week, and you will be patching production under pressure.
For migration support, MapAtlas provides direct developer assistance. Reach out through the contact page or start with the API documentation to evaluate the replacement APIs against your requirements.
Frequently Asked Questions
When exactly do the Google Maps API deprecations take effect?
The Heatmap Layer and Drawing Library were deprecated in August and May 2025 respectively, with removal scheduled for May 2026. DirectionsService and DistanceMatrixService were deprecated on February 25, 2026, also with a May 2026 removal target. After removal, API calls to these services will return errors.
Will my existing Google Maps JavaScript API key still work after May 2026?
Your API key will still work for non-deprecated services. However, any code that calls DirectionsService, DistanceMatrixService, the Heatmap Layer, or the Drawing Library through the Maps JavaScript API will break. You need to migrate those specific calls to replacement APIs before the deadline.
What is the cheapest alternative to the Google Maps Directions API?
MapAtlas offers a Directions API at approximately 70% lower cost than Google's equivalent. The free tier includes 10,000 requests per month, enough to develop and test your migration. Other alternatives include Mapbox, HERE, and OpenRouteService, but MapAtlas provides the closest request/response format to Google's, reducing migration effort.
Can I migrate incrementally or do I need to switch everything at once?
You can migrate incrementally. Each deprecated service is independent, so you can replace DirectionsService first, then DistanceMatrixService, then the visualization libraries. This is actually the recommended approach since it lets you test each replacement in isolation before moving to the next.
Does MapAtlas support the same waypoints and travel modes as Google DirectionsService?
Yes. The MapAtlas Directions API supports driving, walking, and cycling travel modes, plus intermediate waypoints. The request format is slightly different (RESTful endpoint vs. JavaScript class), but the core functionality, multi-stop routing with travel mode selection, is equivalent.

