latlng vs Tile38: geofencing servers compared
Tile38 is the established open-source geofencing server. latlng follows the same collection, object, and fence model, and differs in how it delivers webhooks, authenticates clients, and where it can run. Here is an honest side-by-side.
Reviewed against latlng v0.2.0 and Tile38 1.38.0 · Updated September 27, 2026 · tile38.com · Tile38 on GitHub
Summary
- Same core model: collections, objects, fields, TTLs, NEARBY / WITHIN / INTERSECTS searches, and inside, outside, enter, exit, cross, and roam geofences.
- Tile38 wins on ecosystem: Redis protocol compatibility, a dozen hook destinations, Lua scripting, vector tile output, and years in production.
- latlng wins on delivery and security: durable at-least-once webhooks with dead-lettering, JWT/JWKS auth with per-collection permissions, and a WebAssembly build for the browser.
Feature comparison
| Feature | latlng | Tile38 |
|---|---|---|
| Language and license | Rust, MIT | Go, MIT |
| Maturity | Young project (v0.2.0, first released 2026) | Mature and widely deployed (v1.38), large community and client ecosystem |
| Object types | Point (with optional z), bounding box, geohash, GeoJSON, string | Point (with optional z), bounding box, geohash, GeoJSON, string |
| Searches | NEARBY, WITHIN, INTERSECTS, SCAN, text SEARCH | NEARBY, WITHIN, INTERSECTS, SCAN, SEARCH |
| Query areas | Circle, bounds, geohash, GeoJSON, XYZ tile, quadkey, sector, reference to a stored object | Circle, bounds, geohash, GeoJSON, XYZ tile, quadkey, sector, reference to a stored object |
| Filtering | WHERE ranges, WHERE IN, expressions, MATCH globs, cursor and limit | WHERE ranges, WHEREIN, expressions (including =~ regex), MATCH globs, cursor and limit |
| Output formats | Objects, points, bounds, geohashes, IDs, count; INTERSECTS clipping | Objects, points, bounds, geohashes, IDs, count; clipping; Mapbox Vector Tiles over HTTP |
| Geofence detection | inside, outside, enter, exit, cross, roam; NODWELL for roaming fences | inside, outside, enter, exit, cross, roam; NODWELL for roaming fences |
| Hook destinations | HTTP and HTTPS POST | HTTP, gRPC, Redis, Kafka, MQTT, AMQP, NATS, Amazon SQS, Google Pub/Sub, Azure Event Hubs, Disque, Cloudflare Queues |
| Hook delivery | Durable outbox written atomically with the mutation; exponential backoff, configurable retry budget, dead-letter state, at-least-once with stable event IDs | Local queue file; failed sends are retried every 0.5 s for up to 30 s per message, then dropped. Multiple endpoints act as failover |
| Live subscriptions | Channels over WebSocket and Cap'n Proto streams | Channels over RESP SUBSCRIBE / PSUBSCRIBE; live fences over a kept-open connection |
| Protocols | HTTP/JSON with a generated OpenAPI 3 document, WebSocket, Cap'n Proto RPC | Redis RESP, HTTP, WebSocket, telnet; JSON or RESP responses |
| Client libraries | TypeScript SDK, Rust crates, any HTTP client | Any Redis client, plus dedicated clients for Go, Node.js, Python, TypeScript, Java, Rust, Swift |
| Authentication | Static bearer token, HMAC JWT, asymmetric JWT (PEM or JWKS); per-collection permission claims | One shared server password (requirepass / AUTH) |
| Scripting | None | Lua (EVAL, EVALSHA, read-only variants) |
| Persistence | In-memory or append-only file with compaction, verify, backup and restore; SQLite for embedded use | In-memory with append-only file and AOFSHRINK compaction |
| Replication | Single leader to read-only followers over Cap'n Proto, checksum-based resume | Leader to followers via FOLLOW |
| Operations | Prometheus metrics, structured logs, global and per-principal HTTP rate limits | Prometheus metrics endpoint, INFO / STATS / SERVER commands |
| Runs in the browser | Yes — @latlng/wasm runs the engine in a Web Worker | No |
| Embeddable | Yes — latlng-core is a Rust library with pluggable storage | Designed as a standalone server |
Same model, different emphasis
If you know Tile38, latlng will feel familiar. Both store objects with IDs inside named collections, attach numeric or string fields, expire objects with a TTL, and answer NEARBY, WITHIN, INTERSECTS, SCAN, and SEARCH queries. Both turn any search into a geofence that reports inside, outside, enter, exit, cross, and roam events, and deliver those events to channels or webhooks.
The difference is in what surrounds that model. Tile38 speaks the Redis protocol and fans events out to a long list of message brokers. latlng exposes a typed HTTP/JSON API, treats webhook delivery as durable state, uses JWTs for fine-grained access control, and compiles the same engine to WebAssembly.
SET fleet truck1 POINT 53.55 9.99
NEARBY fleet POINT 53.55 9.99 1000
SETHOOK depot http://10.0.0.5/hook \
NEARBY fleet FENCE DETECT enter,exit \
POINT 53.55 9.99 500 curl -X POST localhost:7421/collections/fleet/objects/truck1 \
-d '{"object":{"Point":{"lat":53.55,"lon":9.99,"z":null}}}'
curl -X POST localhost:7421/collections/fleet/search/nearby \
-d '{"lat":53.55,"lon":9.99,"meters":1000,"options":{}}'
curl -X POST localhost:7421/hooks -d '{
"name": "depot", "endpoint": "http://10.0.0.5/hook",
"def": { "collection": "fleet",
"query": {"Nearby": {"lat":53.55,"lon":9.99,"meters":500,"options":{}}},
"detect": ["Enter","Exit"], "commands": ["Set"] } }' Webhook delivery guarantees
This is the most important practical difference. In Tile38, hook messages go into a local queue file. If the endpoint is unreachable, Tile38 retries every half second, but each message only lives for 30 seconds — after that it is dropped. That is fine for live dashboards, but a receiver that is down for a minute silently misses events.
latlng writes the mutation and its webhook job to the append-only log in one atomic batch, then delivers from a SQLite outbox rebuilt from that log. Failed deliveries back off exponentially (200 ms up to 30 s by default), are retried up to a configurable budget, and end in an inspectable dead-letter state instead of disappearing. Every request carries stable X-LatLng-Event-Id and X-LatLng-Job-Id headers so receivers can deduplicate at-least-once delivery.
The trade-off is reach: latlng only POSTs to HTTP and HTTPS endpoints. If you need events in Kafka, NATS, MQTT, or SQS, Tile38 delivers there directly, while latlng needs a small HTTP relay in front of the broker.
Protocols and ecosystem
Tile38 speaks RESP, so any Redis client in any language can talk to it, and there are dedicated clients for Go, Node.js, Python, TypeScript, and more. Its Lua scripting lets you run custom logic next to the data. latlng has none of that today.
latlng instead offers an HTTP/JSON API described by a generated OpenAPI 3 document, which makes it easy to generate clients or explore the API with standard tooling, plus WebSocket subscriptions and Cap'n Proto RPC for low-overhead native clients.
Security model
Tile38 protects a server with one shared password. Anyone with the password can run every command against every collection.
latlng validates static bearer tokens, HMAC-signed JWTs, and asymmetric JWTs from PEM keys or a JWKS endpoint, so it can sit behind an existing identity provider. Permissions such as objects:write, queries:read, or subscriptions:read are scoped per collection through a claim in the token, and HTTP rate limits can apply per principal.
Running in the browser
latlng's core is portable Rust, so the same engine compiles to WebAssembly. The @latlng/wasm package runs it inside a Web Worker with collections, spatial queries, and geofence hooks — the live map on the latlng homepage is 50 simulated vehicles and 99 Hamburg district geofences evaluated entirely in the browser. Tile38 has no equivalent; browser apps talk to it over the network.
Performance
We don't publish head-to-head numbers, because results depend heavily on hardware, object counts, fence density, and persistence settings. The latlng repository includes a black-box benchmark harness that runs the same scenarios against both servers — make bench-server-tile38 — so you can measure on your own workload. Both keep the working set in memory and use R-tree spatial indexes.
Choose latlng when
- Missing a geofence event is a bug, and you want durable, retried, dead-lettered webhook delivery.
- You need per-client access control via JWTs or an existing identity provider instead of one shared password.
- You want the same engine in the browser for offline or local-first map apps.
- You prefer a typed HTTP/JSON API with an OpenAPI description, or want to embed the engine in a Rust service.
Choose Tile38 when
- You want a mature, battle-tested server with a long production track record.
- Your stack already speaks Redis, or you need clients in many languages today.
- Geofence events must go straight to Kafka, NATS, MQTT, AMQP, SQS, Pub/Sub, or Event Hubs.
- You need Lua scripting or Mapbox Vector Tile output.
Frequently asked questions
Is latlng a drop-in replacement for Tile38?
No. The data model and geofence concepts map almost one-to-one, but latlng does not speak the Redis RESP protocol, so clients need to switch to latlng's HTTP/JSON API, WebSocket transport, or TypeScript SDK.
Does Tile38 guarantee webhook delivery?
Tile38 queues hook messages in a local file and retries failed sends every half second, but each message expires after 30 seconds and is then dropped. latlng keeps webhook jobs in its durable log, retries with exponential backoff, and moves exhausted jobs to a dead-letter state.
Can latlng send geofence events to Kafka or MQTT?
Not directly. latlng delivers webhooks over HTTP and HTTPS only, and streams live events over WebSocket and Cap'n Proto. To reach a message broker, point the webhook at a small HTTP relay that publishes to the broker.
Which one is faster?
It depends on the workload. Both are in-memory engines with R-tree indexes. The latlng repository ships a benchmark harness (make bench-server-tile38) that runs identical scenarios against both servers so you can compare on your own hardware and data.
More comparisons
Redis GEO commands index points inside a sorted set. latlng adds polygons, geofence events, and webhooks on top of the nearby search Redis already does well.
latlng vs PostGISPostGIS is the spatial SQL database of record. latlng is an in-memory engine for live positions and push-based geofence events — often used next to it.