Find the nearest Tesla Superchargers by real road distance β address in, routed results out.
Unofficial Β· self-hostable Β· OpenStreetMap-based Β· data refreshed daily
- What it does
- Features
- Why the data stays accurate
- Quick start
- Configuration
- API reference
- How it works
- Swapping the routing provider
- Development & testing
- Troubleshooting
- Legal & fair use
- License
You type an address (anywhere in Europe). SuperchargeCompass geocodes it, finds the nearest Tesla Superchargers by actual driving distance (not air line), draws the route on an OpenStreetMap map, and lists several alternatives with distance, drive time, stall count, and whether the site is open to non-Tesla EVs.
Everything the web UI does is also available as a JSON API, so you can integrate it into your own tools.
| Feature | |
|---|---|
| π | Address β nearest Superchargers, ranked by real road distance or drive time (OpenRouteService matrix) |
| π’ | Multiple results (3 / 5 / 10) β not just the single closest |
| πΊοΈ | Routes on the map β click any result to route to it, or enable show all routes to compare them in distinct colours |
| π | "Coming soon" toggle β include planned / under-construction sites |
| π | "Open to all EVs" filter β only sites usable by non-Tesla vehicles |
| π | Daily data refresh from two sources, with a stale-data banner if it ever fails |
| π§© | JSON API for machines β same capabilities as the UI |
| π | Swappable routing backend β OpenRouteService today, self-hosted OSRM tomorrow |
Tesla's own location feed keeps stale "coming soon" ghosts β sites still flagged βTarget opening Q1 2023β years after they actually opened (~19 % of its coming-soon entries when we measured). SuperchargeCompass therefore merges two sources on every daily grab:
| Source | Role |
|---|---|
Tesla all-locations feed |
Base: official coverage, names, coordinates, coming-soon flags |
| supercharge.info community DB | Corrector/enricher: fixes stale coming soon β open, fills stall counts and open-to-all-EVs flags (coordinate match < 600 m) |
Failure behaviour is deliberately conservative:
- One source unreachable β the other is used alone.
- Both fail β the grabber refuses to overwrite the last good data file, and the UI shows a stale-data warning banner instead of silently serving nothing.
Requirements: Node.js β₯ 20.6 and a free OpenRouteService API key (free tier β 2,000 requests/day).
git clone https://github.com/HECer/supercharge-compass.git
cd supercharge-compass
npm install
cp .env.example .env
# open .env and set: ORS_API_KEY=<your key>
npm run grab # fetch supercharger data β data/superchargers.json
npm start # serve the app β http://localhost:3000That's it. The running server re-grabs the data automatically every day at 03:15
(node-cron). If you don't keep the server running 24/7, schedule npm run grab with your
OS scheduler (cron / Task Scheduler) instead.
All configuration lives in .env (loaded via Node's --env-file):
| Variable | Default | Purpose |
|---|---|---|
PORT |
3000 |
HTTP port |
ORS_API_KEY |
β (required) | OpenRouteService key (geocoding + routing) |
ORS_BASE_URL |
https://api.openrouteservice.org |
Point at a self-hosted ORS instance |
ROUTING_PROVIDER |
ors |
Routing backend selector |
DATA_FILE |
data/superchargers.json |
Location of the grabbed dataset |
curl "http://localhost:3000/api/nearest?address=Alexanderplatz%201,%20Berlin&limit=5"
curl "http://localhost:3000/api/nearest?lat=52.52&lon=13.41&comingSoon=true&sort=duration"| Param | Type | Default | Meaning |
|---|---|---|---|
address or lat+lon |
string / number | β | Origin. address is geocoded; coordinates skip geocoding |
limit |
number | 5 |
Number of results |
sort |
distance | duration |
distance |
Ranking criterion |
comingSoon |
boolean | false |
Include planned sites |
openToAllEvs |
boolean | false |
Only sites open to all EVs |
Example response (click to expand)
{
"origin": { "lat": 49.0355, "lon": 8.7186, "label": "MerianstraΓe 10, Bretten, BW, Germany" },
"results": [
{
"id": "tesla-bruchsalsupercharger",
"name": "Bruchsal Supercharger",
"lat": 49.1292,
"lon": 8.5855,
"address": "17 KammerforststraΓe, 76646 Bruchsal, Germany",
"status": "open",
"openToAllEvs": true,
"stallCount": 14,
"distanceMeters": 22648,
"durationSeconds": 1804
}
],
"route": {
"toId": "tesla-bruchsalsupercharger",
"geometry": { "type": "LineString", "coordinates": [[8.7185, 49.0356], ["β¦"]] },
"distanceMeters": 22648,
"durationSeconds": 1804
},
"meta": {
"dataTimestamp": "2026-07-14T14:41:18.366Z",
"source": "tesla+supercharge.info",
"count": 4555,
"stale": false
}
}Errors: 400 missing origin Β· 422 address could not be geocoded Β· 503 routing backend unavailable.
curl "http://localhost:3000/api/route?fromLat=49.03&fromLon=8.71&toLat=49.12&toLon=8.58"Returns { geometry (GeoJSON LineString), distanceMeters, durationSeconds }.
Used by the UI to draw the route to any clicked result. 400 on missing coordinates.
curl "http://localhost:3000/api/superchargers?comingSoon=false&openToAllEvs=true"Returns { superchargers: [...], meta } β every normalized site, filterable. Each site:
{
"id": "tesla-pforzheimsupercharger1",
"name": "Pforzheim",
"lat": 48.9051, "lon": 8.6542,
"address": "Pforzheim, Germany",
"status": "open",
"openToAllEvs": true,
"stallCount": 20,
"source": "tesla"
}status is "open" or "coming_soon". stallCount may be null when unknown.
Returns { dataTimestamp, source, count, stale }. stale is true when the dataset is
older than 48 hours β treat results with caution then.
grabber (daily cron + npm run grab)
Tesla all-locations βββ
βββ merge (coordinate match < 600 m)
supercharge.info ββββββ β
βΌ
data/superchargers.json
β (loaded in-memory)
Browser (Leaflet + OSM tiles) βΌ
β Express API βββΊ datastore
βββ /api/nearest βββββββββββββββββ€
β 1. geocode address (ORS, 1 call)
β 2. haversine pre-filter (in-memory, 0 calls)
β β 25 nearest candidates
β 3. distance matrix 1 β 25 (ORS, 1 call)
β 4. sort by road distance/time
β 5. route geometry for #1 (ORS, 1 call)
The in-memory haversine pre-filter means a search costs ~3 external requests total, no matter how many thousands of sites are in the dataset. Routes to other results are fetched lazily on click and cached client-side.
src/routing/index.js is a small factory keyed on ROUTING_PROVIDER. A provider is any
object with three async methods:
geocode(address) // β { lat, lon, label } | null
matrix(origin, destinations) // β [{ distanceMeters, durationSeconds }, β¦]
route(origin, destination) // β { geometry, distanceMeters, durationSeconds }All providers take an injectable fetchImpl so tests never touch the network. To go
self-hosted, add src/routing/providers/osrm.js, register it in the factory, set
ROUTING_PROVIDER=osrm β nothing else changes.
npm test # 52 tests, Node's built-in test runner β zero network access- External calls (
fetch) are dependency-injected and faked in every test. - Fixtures for both data sources live in
test/fixtures/. - Modules under test in isolation: geo, datastore, routing provider, nearest-search orchestration, both parsers, source merging, grabber safety, HTTP API, server wiring, frontend serving.
| Symptom | Cause & fix |
|---|---|
EADDRINUSE on start |
Port taken (often a previous instance). Change PORT in .env or stop the old process. Restart the server after every .env change. |
UI says "Dienst momentan nicht verfΓΌgbar" / API returns 503 |
ORS_API_KEY missing/invalid, or ORS rate limit hit. Verify the key, wait, retry. |
npm run grab reports tesla: β¦ 403 |
Tesla's endpoint rejected the request; the grabber automatically falls back to supercharge.info. Nothing to do. |
| Stale-data banner in the UI | Last successful grab is > 48 h old. Run npm run grab and check its output. |
| A site's status looks wrong | Data comes from Tesla + supercharge.info; some sites can't be cross-matched. See Why the data stays accurate. |
- Not affiliated with, endorsed by, or connected to Tesla, Inc. βTeslaβ and βSuperchargerβ are trademarks of Tesla, Inc., used here solely to describe compatibility (nominative use).
- Location data is fetched once per day from Tesla's public website and supercharge.info. Accuracy is not guaranteed β always verify before you drive.
- Map data Β© OpenStreetMap contributors. Geocoding & routing by OpenRouteService β respect their rate limits and terms of service.
MIT Β© HECer