OpenStreetMap Overpass but cached

OpenStreetMap data is huge. Like really really huge. Its the whole planet earth afterall. So huge in fact that so far I am using a separate server to host my very own, up-to-date OpenStreetMap planet instance that I can query against with the Overpass-API format.

Overpass is quite handy for all sorts of use-cases, like searching for very specific information on the map – like amenities (toilets, benches, ATMs,…).

So a query like this (you have to set bbox to the actual bounding box coordinates):

Will produce a data-set representing all toilets inside of that bounding box on the map. This will look a lot like this:

And of course this is lots of effort to sieve through all the millions of nodes inside of the bounding-box and filtering out the right ones.

To produce the example above my server needs roughly 27630 milliseconds or just under 28 seconds to process all that data (which is 13668 toilets….).

For the amount of data and the processing required this isn’t all that bad. The caveat: if you rerun that request it will take the almost exact same time. It’s just a lot of data and the limit here is SSD-read speeds and compute capacity.

Now I happen to have written an app that makes use of Overpass-Queries as its main purpose: It finds you amenities like Toilets. It does implement it’s own caching on client side, so for users the map is fast after the actual load, no matter how often they come back to that section of the map. But that client-side caching does not scale with lots of users.

With the recent rewrite of my app the userbase has expanded. Therefore lots more users actually use my app. And apparently they run lots of overpass queries. To relieve server load and required resources I came up with a simple vibe code prompt:


I have the following idea and would like to develop a plan with you for a specification on how this idea can best be implemented with Codex.

Current situation:
So far, I have been running a full OpenStreetMap Overpass Server. This comes with enormous resource requirements because the entire OSM world map, including all metadata, must be managed and kept up to date.

My use case (filtering for toilets/amenities), however, is relatively limited and can be summarized into fixed queries. When I look at how much data is actually affected worldwide, I would estimate that instead of the 500 GB world map, less than 100 MB of real useful data is relevant for my application.

The idea:
I want to program a transparent Overpass API proxy (https://wiki.openstreetmap.org/wiki/Overpass_API) that only responds to appropriately formulated Overpass queries from API users.

The query:

node
  [amenity=toilets]
  ({{bbox}});
out body meta;>;out skel qt;

I want the Overpass API proxy to cache all potential data (with a configurable TTL) and query results from an underlying Overpass API server, fill the cache, and return bounding-box results according to the query.

Any bounding boxes should be queryable — but always with a fixed amenity.

The task:
Create a specification, program flow, and implementation instructions for a program that uses Node.js as the base for the Overpass API proxy and Redis as the intermediate storage/cache.
The whole thing should be deployable as a Docker container and have both a configurable TTL and a configurable upstream Overpass API server.

Bonus:
It would be a plus if the actual amenity could be flexibly chosen.
All metadata returned by the Overpass server should be correctly stored and, upon request, reassembled into bounding boxes by the Overpass API proxy.


Several steps with OpenAIs Codex and Cursor led to an actual implementation of that idea.

The result: The exact same query, when run again, takes less than 2 seconds now:

I have, as usual, open sourced that tool. So you can try for yourself, if you happen to have a use case. If you want you can try it out best with Overpass Turbo in your browser, while setting up the Overpass-Proxy on a server (docker instructions included in the box).

Sourcecode: https://github.com/bietiekay/Overpass-Proxy

Rewriting an Old Friend: The Toilet Finder App, Version 2

Back in 2015 I built a small app because I was traveling a lot and kept running into the same slightly ridiculous, slightly stressful situation:
you never really know where the next public toilet is until it becomes… quite an urgent matter.

So I hacked together a simple iOS app, used OpenStreetMap data, showed nearby toilets, and uploaded it to the App Store.
It was called Toilet Finder.
It worked. And then it just… stayed that way for almost a decade.

Why a rewrite?

At some point, code just ages out of its time.
The original app was built in the early days of iOS development with ObjectiveC as the programming language.

It kept working but every time I tried to fix something, I ended up spelunking through a maze of compatibility shims and ancient delegate patterns.
A piece of software that functioned but didn’t feel maintainable anymore.

So I started over.

The same idea, just cleaner

The essence of the app hasn’t changed:

“Show me nearby toilets, instantly, without tracking me, and without subscriptions.”

But everything underneath was rewritten from scratch.
The new version is entirely SwiftUI, with structured concurrency and Apple’s MapKit for rendering and routing.

That change alone cut away thousands of lines of glue code.
Apple Maps now provides both the background map tiles and the walking routes directly inside the app — no context switch to another app.

Open data, still the foundation

From the very beginning, the data came from OpenStreetMap (OSM), and it still does. It’s hard to overstate how valuable that project is — an open, crowd-maintained map of the entire planet, full of tiny details that commercial datasets rarely bother with. And crowd-maintained means: you can add something anytime yourself (which I do a lot when I am travelling).

Every public toilet in OSM carries a little bundle of metadata: whether it’s wheelchair accessible (wheelchair=yes), has a baby-changing table (changing_table=yes), costs money (fee=yes), or is unisex.

That richness makes OSM perfect for this use case — but only if you can query it efficiently.

About Overpass – and why I run my own

That’s where Overpass comes in.
Overpass is a specialized database engine built to answer complex questions about OSM data.
Instead of downloading the entire world, you can ask things like:

node
  [amenity=toilets]
  ({{bbox}});
out;

This means: “Give me all objects tagged as toilets within this bounding box.”

The result is a clean JSON structure that contains just what’s needed — coordinates, tags, and nothing else. It’s elegant, but also resource-intensive.

The public Overpass servers are shared by thousands of users worldwide. To avoid adding load or hitting rate limits, I decided early on to operate a dedicated Overpass instance specifically for this app.
It runs on my own infrastructure, continuously synchronised with the global OSM database, and tuned for quick bounding-box queries.

That setup means the app never touches the public endpoints. Every user query goes against my own server, which mirrors the OSM planet file and indexes it for exactly this use case. And my servers do not log anything. Every request is stateless and gone after it’s done.

Privacy by design

Because the app directly queries Overpass, there’s no need for user accounts, analytics, or any logging. The app simply constructs a bounding box around your visible map area and sends it to the Overpass instance.

The result is just a list of toilets — which are then drawn locally on the map.

The new logic under the hood

The rewrite gave me a chance to rethink the app’s internal logic.
In the old version, every pan or zoom triggered a new request. It worked, but it was noisy — and sometimes slow.

Now, the app uses a spatial cache. It remembers which regions of the map you’ve already seen and reuses them instantly. If you return to the same area later (even offline), the toilets appear immediately, and a background task quietly checks for updates.

There’s also clustering now. Instead of dropping hundreds of overlapping pins in dense city areas, the app groups nearby toilets into a single marker that expands smoothly as you zoom in.
It keeps the map readable — and strangely satisfying to explore.

Walking routes, finally in-app

One of the small frustrations with version 1 was that navigation meant switching to the Maps app.
Now, when you tap “Show walking route,” the path appears right there, drawn in green on the same map.

That might sound like a detail, but it changes how it feels to use the app.
You don’t lose context; the map doesn’t disappear. You tap, it shows, you walk.

Looking back

When I first uploaded Toilet Finder in 2015, I never imagined it would still exist ten years later.
It was a small weekend project, built to solve a personal nuisance.
But people started to use it and still do. Now the app itself is translated to multiple languages. The old version knew English. Version 2.0 comes with English, German, French, Spanish and Japanese.

Rewriting it in 2025 wasn’t about chasing new trends; it was about giving an old idea a proper modern home.
The app feels the same, but lighter, smoother, and more trustworthy.

You can get the new version here: Toilett Finder in the Apple AppStore