Early this month, we moved every Static Maps request to a new rendering system. The API didn't change, so you don't need to update anything on your side.

Responses got faster and more consistent. The old system was fast, most of the time. The problem was the slowest requests: 1%-5% of them regularly took 1-4s or more, even with caching. When traffic spiked, we kept the service up by slowing requests down or rejecting them.

Fewer Tiles, Faster Maps

We built our original Static Maps API by stitching together tiles from our tile servers. Like web maps, we fetched tiles from our internal systems, stitched them together, and overlaid your pins, lines, and labels to render the final static map image. This approach began to show its limits as our services scaled, and spikes in Static Maps often slowed all our Map products. We needed to fix that, so we completely overhauled the system.

We rewrote Static Maps in Rust using MapLibre Native. Instead of stitching tiles together to create the static map image, we now render the entire map as one image, with all overlays rendered directly in MapLibre Native. As a result, median response time halved. The slowest 1% of requests went from up to 8s to about 1s.

Here's a typical hour before the change. You can't even see the p75 or p50 times, because p99 dominates the timing so much:

Static Maps response times before the rebuild, with p99 pinned at 8 seconds during spikes and p75 and p50 compressed against the bottom of the chart

Before, all percentiles

The same hour before the rebuild with p99 removed, showing p75 peaking near 1 second and p50 below it

Before, p75 and p50

Static Maps response times after the rebuild, with p99 holding near 1 second and no spikes

After, all percentiles

The same hour after the rebuild with p99 removed, showing p75 and p50 flat and well under the previous baseline

After, p75 and p50

The results speak for themselves. Worst-case, loaded performance is now faster than the previous system's baseline.

Here's the before and after. Each row shows how long it takes for 50%, 95%, or 99% of requests to finish:

PercentileBeforeAfter
p50~333ms~170ms
p951-4s600-700ms
p992-8s~1s

Handling Traffic Spikes Without Rejected Requests

Because the new system renders maps directly, we can now scale automatically with load. Before, absorbing a spike meant adding capacity by hand or throttling requests. On launch day, a traffic spike we see regularly came through in full, with no rate limiting. For months, we'd slowed that same spike down or rejected part of it.

With this headroom and ability to scale on demand, we've raised rate limits on Static Maps requests. Your map tiles also benefit. Our tile servers used to render static maps, so a burst of static map traffic added load there. Static Maps now runs on its own stack.

Raster map tile response times before the rebuild, with p99 spiking to roughly 1 second

Raster map tiles, before

Raster map tile response times after the rebuild, with p99 holding between 400 and 650 milliseconds

Raster map tiles, after

But Wait, There's More

Static Maps now accepts fractional zoom levels, such as 12.5. You can frame a map exactly, instead of choosing between two whole zoom levels that are each a little off. Each image also now renders in a single pass. Labels no longer get cut off at internal boundaries, and a style or data update can't produce an image with mismatched sections.

What's Next

We're still tuning performance and reliability as the new system settles in. By building a faster, more stable Static Maps platform and relieving our other Maps systems of the burden of Static Maps, we not only make every response faster, but also allow us to launch more of your most-requested features across our entire Maps platform.

As always, reach out to us at support@stadiamaps.com with any questions.