latlng vs PostGIS: live geofencing vs spatial SQL
PostGIS is the spatial database of record. latlng is an in-memory engine for objects that move and the events they trigger. They solve different problems, and they often work best side by side.
Reviewed against latlng v0.2.0 and PostGIS 3 on PostgreSQL · Updated September 27, 2026 · postgis.net · PostGIS docs
Summary
- PostGIS wins on depth: SQL, transactions, disk-backed scale, hundreds of spatial functions, and the whole GIS ecosystem.
- latlng wins on liveness: in-memory position updates, built-in enter/exit/cross/roam geofences, and durable webhook delivery.
- They complement each other: latlng for the current state and events, PostGIS for history, analytics, and authoring fence polygons.
Feature comparison
| Feature | latlng | PostGIS |
|---|---|---|
| What it is | In-memory geospatial object engine and geofencing server | Spatial extension for the PostgreSQL relational database |
| License | MIT | GPL-2.0-or-later (PostgreSQL itself uses the PostgreSQL License) |
| Data model | Collections of objects keyed by ID, with fields and JSON documents | SQL tables with any schema, foreign keys, and joins |
| Geometry | Points, bounding boxes, geohashes, and GeoJSON geometries in WGS84 | Full OGC Simple Features, geography type, curves, 3D/4D, raster, and topology in any coordinate system |
| Spatial operations | Search predicates: nearby, within, intersects, with optional clipping | Hundreds of ST_ functions: buffers, unions, area, length, simplification, reprojection, and more |
| Query language | HTTP/JSON commands | SQL |
| Indexing | In-memory R-tree | GiST, SP-GiST, and BRIN indexes on disk; KNN ordering with the <-> operator |
| Dataset size | Working set must fit in memory | Disk-backed; scales well beyond RAM |
| Write profile | Built for continuous position updates to the same objects | Each update writes a new row version, WAL, and index entries; high-rate updates need vacuum and table tuning |
| Transactions | Each command is atomic; no multi-statement transactions | Full ACID multi-statement transactions |
| Geofence events | Built in: inside, outside, enter, exit, cross, and roam detection | None built in; implement with triggers plus NOTIFY, or change data capture |
| Event delivery | Durable HTTP webhooks with retries and dead-letter; WebSocket and Cap'n Proto streams | LISTEN/NOTIFY reaches only currently connected sessions; durable delivery needs an outbox table or CDC pipeline |
| Authentication | Bearer tokens and JWT/JWKS with per-collection permissions | PostgreSQL roles, GRANTs, and row-level security |
| Replication and backup | Append-only file with verify, backup, restore; single-leader follower replication | WAL archiving, point-in-time recovery, streaming and logical replication, mature HA tooling |
| Ecosystem | Young project; TypeScript SDK, Rust crates, WebAssembly build for the browser | QGIS, GeoServer, GDAL/ogr2ogr, vector tile servers, every ORM, managed on all major clouds |
Different jobs, not rivals
PostGIS is the spatial database of record: durable, transactional, queryable with SQL, and capable of almost any geometric computation. If you need to store parcels, road networks, or years of trip history and run analytics over them, PostGIS is the right tool and latlng is not trying to replace it.
latlng is built for the other half of many location systems: the live state of things that move, and reacting the moment one of them crosses a boundary. It keeps current positions in memory, evaluates geofences on every update, and pushes events out as webhooks or streams.
CREATE TABLE fleet (
id text PRIMARY KEY,
geom geography(Point, 4326)
);
CREATE INDEX ON fleet USING gist (geom);
INSERT INTO fleet VALUES
('truck1', ST_MakePoint(9.99, 53.55))
ON CONFLICT (id) DO UPDATE SET geom = EXCLUDED.geom;
SELECT id FROM fleet
WHERE ST_DWithin(geom, ST_MakePoint(9.99, 53.55)::geography, 1000); 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":{}}' Geofencing on PostGIS
PostGIS can tell you whether a point is inside a polygon, but it won't tell you when that changes. A typical do-it-yourself setup adds a trigger on the positions table that runs ST_Contains against a fences table, compares the result with the previous membership stored per object, and calls pg_notify for each transition.
That works, with caveats: NOTIFY only reaches sessions that are listening at that moment, payloads are limited in size, and the fence check runs inside every position write. Reliable delivery usually means an outbox table plus a worker, or a change-data-capture pipeline such as logical decoding into a message broker.
latlng does this natively. Fences are stored queries with inside, outside, enter, exit, cross, and roam detection. Matching events are written to the durable log in the same batch as the mutation and delivered as webhooks with exponential backoff, retry budgets, and dead-lettering.
High-frequency position updates
PostgreSQL's MVCC design writes a new row version for every UPDATE. When the geometry column is indexed, updates can't use the heap-only-tuple optimization, so each position change also touches the spatial index and the WAL. For fleets reporting every few seconds, that means careful autovacuum tuning, fillfactor settings, or an append-only table partitioned by time.
latlng keeps the current position of each object in memory and updates its R-tree in place, with optional append-only-file persistence that group-commits writes. It is designed for exactly this "same object, new position, again and again" workload.
Using them together
A common architecture sends device updates to latlng for real-time indexing and geofencing, and writes the same stream (or latlng's webhook events) into PostGIS for history, reporting, and heavy spatial analysis. Fence polygons can be authored and versioned in PostGIS and pushed to latlng as GeoJSON hooks.
Choose latlng when
- Positions change constantly and you care about the current state, not every historical row.
- You need enter, exit, cross, or roam events pushed to other services reliably.
- The live dataset fits in memory and you want low-latency nearby and within queries.
- You want the same spatial engine in the browser for offline or local-first apps.
Choose PostGIS when
- You need a durable system of record with SQL, joins, and multi-statement transactions.
- Your data is larger than memory, or includes rasters, networks, or complex topology.
- You need rich geometry processing: buffers, unions, reprojection, measurements.
- You rely on GIS tooling such as QGIS, GeoServer, or GDAL, or want a managed database.
Frequently asked questions
Can PostGIS do real-time geofencing?
Not out of the box. PostGIS evaluates spatial predicates such as ST_Contains or ST_DWithin, but it has no geofence objects or enter/exit events. You can build them with triggers that track previous membership and call pg_notify, or with change data capture, but delivery, retries, and state tracking are up to you.
Is latlng a replacement for PostGIS?
No. latlng is an in-memory engine for live object positions and geofence events. It has no SQL, joins, or multi-statement transactions, and only a focused set of spatial predicates. Many systems use latlng for real-time state and PostGIS for history and analysis.
Why not just store live positions in PostgreSQL?
You can, and at moderate update rates it works well. At high rates, every position update creates a new row version, WAL traffic, and spatial index maintenance, which increases vacuum load and write amplification. latlng updates positions in memory and persists them to an append-only log instead.
Can latlng use PostGIS polygons as geofences?
Yes. Export fences from PostGIS with ST_AsGeoJSON and register them in latlng as hook or channel geofences with a GeoJSON area. The latlng CLI can also create hooks directly from GeoJSON files.
More comparisons
Two geofencing servers with the same object and fence model. Tile38 brings RESP, Lua, and a dozen hook destinations; latlng brings durable webhooks, JWT auth, and a browser build.
latlng vs Redis GEORedis 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.