Fastest Geospatial Desktop Stack
Benchmarks across the three layers of a geospatial desktop app — rendering, shell, and data
path — measured on an Apple M2 Max, 120 Hz. Source:
geo-desktop-bench.
Verdict: Tauri + deck.gl + DuckDB/PMTiles — single-file, server-less,
offline-capable. Tauri wins the metrics that constrain a desktop app (3.2 MB binary, ~97 MB
RAM) by ~86× and ~4.5× over Electron; deck.gl renders to millions of points at 120 fps;
DuckDB answers spatial queries in ~1.5 ms and PMTiles serves vector tiles with no server.
Live demos
The desktop capstone (DuckDB-on-Rust in Tauri) is native — see the
repo.
The web capstone above is the in-browser equivalent (DuckDB-WASM).
Rendering — deck.gl vs MapLibre vs raw WebGL2
Same synthetic point cloud, same deterministic camera path, frame-time percentiles (8.33 ms = a 120 Hz frame).
| points | WebGL2 (raw) | deck.gl | MapLibre |
| 100k | 120 fps | 120 fps | 120 fps |
| 1M | 120 fps | 120 fps | 120 fps¹ |
| 3M | 120 fps | 105 fps | — |
| 10M | 97 fps | 40 fps | — |
- At ≤1M points the engine doesn't matter — all three pin the refresh cap.
- The wall shows at 3M+: raw WebGL2 stays smooth to 10M; deck.gl's abstraction costs ~2.4× throughput at the extreme.
- ¹ MapLibre's GeoJSON path doesn't fail on FPS — it fails on load: 1M points = 9.5 s to first frame (main-thread tiling). Past ~1M, use vector tiles (the PMTiles demo), not a GeoJSON source.
- Time-to-first-render: deck.gl ~33 ms flat (GPU projection) beats raw WebGL2's CPU loop (381 ms @10M).
Desktop shell — Tauri vs Electron
| metric | Tauri | Electron | winner |
| app size | 3.2 MB | 275 MB | Tauri ~86× |
| idle RSS | ~97 MB² | ~438 MB | Tauri ~4.5× |
| cold start | 429 ms³ | 259 ms³ | ~tie |
| IPC / call | 217 µs | 52 µs | Electron ~4× |
- ² Tauri RSS undercounts on macOS — WKWebView's WebContent is a system-hosted process outside the app tree, so the real gap is smaller (but Electron is clearly heavier).
- ³ Different zero-points (Tauri = process entry; Electron = post-Chromium-boot), so the startup comparison isn't apples-to-apples — not a real win for either.
- Embedding DuckDB takes the Tauri binary 3.2 MB → ~82 MB stripped — still far under Electron's 275 MB shell before any app code.
- Electron's only clear edges: per-call IPC and full WebGPU (WKWebView gates it).
Data path — DuckDB-spatial & PMTiles
| operation | latency |
DuckDB bbox · plain lon/lat BETWEEN (1M rows) | 1.5 ms |
DuckDB bbox · ST_Within + R-tree | 39 ms |
DuckDB k-nearest 50 · ST_Distance | 4.7 ms |
PMTiles getZxy — cold (read + decode) | 0.57 ms |
PMTiles getZxy — warm (cached) | 0.49 ms |
- For an axis-aligned box a scalar column range beats the spatial predicate ~25× — spatial functions earn their cost on complex geometry, not rectangles.
- DuckDB is embedded (Rust side of Tauri) — no network, no serialization. PMTiles is a single file, range-read off disk/CDN — no tile server.
Method & caveats
- Rendering: deterministic web-mercator camera path, warm-up discarded, frame-time percentiles (rAF is refresh-capped, so the tail — p95/p99/jank — is the signal, not mean FPS). Run in Firefox; reps=1.
- Shell size:
tauri build (release, stripped, LTO) vs electron-builder --dir (unsigned). RSS sampled across the process tree over 5 launches.
- All numbers are one machine (M2 Max), point-in-time, and reproducible from the repo — directional, not authoritative leaderboards.