PostGIS Foundations
PostGIS is a Postgres extension that teaches the database how to store, compare, and search shapes in space, not just rows of scalar values.
This page builds the conceptual model behind that: what a coordinate reference system actually is, why geometry and geography exist as separate types, and how spatial indexing makes "what's nearby" a fast question instead of a full table scan.
Summary
- Core Idea: PostGIS adds spatial types and operators to Postgres so that "where" becomes a queryable, indexable property of a row, just like "when" or "how much."
- Why It Matters: Location-aware features like delivery zones, geofencing, and proximity search need geometry-aware storage and indexing that a plain numeric column cannot provide.
- Key Concepts: coordinate reference system (CRS), SRID, geometry, geography, spatial index, GiST.
- When to Use: Reach for this mental model when deciding how to reason about SRIDs, explaining why spatial indexes behave differently from B-tree indexes, or onboarding someone new to spatial data modeling.
- Limitations / Trade-offs: Spatial correctness depends entirely on tracking coordinate reference systems consistently, and getting that wrong produces results that look plausible but are quietly incorrect.
- Related Topics: geometry vs geography types, GiST spatial indexing, PostGIS performance tuning, tile server architecture.
Foundations
A pair of numbers like (-73.99, 40.75) is not a location by itself, it is only a location once you know which coordinate system those numbers are measured in.
That coordinate system is called a coordinate reference system, or CRS, and it defines the origin, units, and shape of the earth model the numbers are plotted against.
PostGIS identifies each CRS with a numeric SRID, and the most common one for GPS and web maps is SRID 4326, which represents raw latitude and longitude on the WGS84 model of the earth.
Every geometry or geography value in PostGIS carries its SRID along with it, so two shapes can only be compared meaningfully once the database knows they share, or can be converted to, the same reference system.
PostGIS represents spatial data with two conceptually different types, and the difference is not cosmetic.
geometry treats the earth as a flat plane and does its math with ordinary planar geometry, which is fast and accurate as long as the area covered is small enough for flatness to be a reasonable approximation.
geography treats the earth as a sphere or spheroid and does its math with geodesic calculations, which stays accurate across large distances at the cost of more computation.
A useful analogy is a paper map versus a globe: a paper map (geometry) is simple and fast to measure on, but it distorts as the area gets larger, while a globe (geography) stays accurate everywhere but is more work to compute with.
Choosing between them is really a choice about how much of the earth's curvature the data needs to respect, not a choice about which type is "better."
The deep mechanics of that choice, including which SRID to pick for which use case, belong to the geometry-vs-geography comparison elsewhere in this section, and this page only needs the conceptual split to build on.
Mechanics & Interactions
PostGIS does not exist as a separate spatial database bolted onto Postgres, it exists as types and operators registered inside Postgres's own extensibility system.
That matters because it means spatial columns participate in the same transactions, backups, and replication as every other column in the same table.
Searching for "everything within 5 kilometers" naively would require computing an exact distance calculation against every row in a table, which does not scale.
Spatial indexing exists to avoid that, and it works by a two-phase idea: first narrow candidates cheaply, then confirm precisely.
The cheap first phase replaces every complex shape with its bounding box, the smallest rectangle that fully contains it, because comparing rectangles is far cheaper than comparing polygons.
Postgres's GiST (Generalized Search Tree) access method is what makes that first phase an index rather than a scan, by organizing bounding boxes into a tree where nearby shapes cluster together in the same branches.
A GiST spatial index quickly eliminates shapes whose bounding boxes cannot possibly satisfy the query, leaving only a small candidate set.
The second phase then runs the exact geometric test, such as ST_DWithin or ST_Intersects, only against that small candidate set to get a precise answer.
This two-phase pattern is why spatial queries scale: the expensive exact math only ever runs against a handful of rows instead of the whole table.
-- Conceptually, a spatial predicate is answered in two phases:
-- 1. GiST narrows by bounding-box overlap (the && operator)
-- 2. The exact function confirms the real shape
SELECT id FROM stores
WHERE geom && ST_Expand(:query_point, 5000) -- cheap bounding-box prefilter
AND ST_DWithin(geom, :query_point, 5000); -- exact geometric confirmationThis is also why a spatial index behaves nothing like a B-tree: a B-tree assumes values sort along a single line, while GiST assumes values overlap in multi-dimensional space and has no single sort order to lean on.
Advanced Considerations & Applications
PostGIS's type system generalizes past geometry and geography into optional extensions like postgis_topology for shared-edge networks and postgis_raster for grid-based imagery, and each one extends the same core idea of typed spatial data with matching operators and indexes.
Coordinate reference system mistakes are one of the most common production failures in spatial systems, because a query mixing SRID 4326 with a projected SRID can silently return numerically valid but geographically meaningless distances.
At large scale, storing every shape at full precision imposes a real index and I/O cost, and simplifying geometries before indexing them is a common way to keep the bounding-box prefilter cheap without changing the underlying data model.
Spatial systems typically split responsibilities between Postgres as the transactional system of record and a dedicated tile server for rendering, because PostGIS optimizes for correctness and joins, not for streaming pre-rendered map tiles at high request volume.
Observability for spatial features should include SRID auditing and ST_IsValid checks on ingested geometry, because invalid or mismatched shapes tend to fail silently rather than throwing obvious errors.
The architectural throughline is the same one pgvector demonstrates elsewhere in this stack: an extension earns real performance by extending Postgres's existing type, operator, and index framework rather than working around it.
| Approach | Strength | Weakness | Best Fit |
|---|---|---|---|
| Plain numeric lat/lon columns | Simple, no extension required | No spatial indexing or geometric operators | Storing a single point with no proximity queries |
| PostGIS geometry/geography with GiST | Fast, indexed, exact spatial queries inside transactions | Requires SRID discipline and index maintenance | Delivery zones, geofencing, spatial joins |
| External GIS engine or tile service | Optimized for rendering and standard OGC protocols | Separate system, eventually consistent with Postgres | High-volume map tile serving |
Common Misconceptions
- "A latitude and longitude pair is a complete location" - the reality is that coordinates are meaningless without a known coordinate reference system, which is exactly what the SRID records.
- "geometry and geography are interchangeable" - the reality is that they encode different earth models, and using the wrong one for the wrong distance produces results that look valid but are wrong.
- "Spatial indexes work like B-tree indexes on coordinates" - the reality is that GiST indexes multi-dimensional overlap, with no single sortable order, so it behaves fundamentally differently.
- "An index alone guarantees correct spatial results" - the reality is that GiST only narrows candidates by bounding box, and the exact geometric function still has to confirm the real answer.
- "PostGIS replaces the need for a tile server" - the reality is that PostGIS is optimized for storage, joins, and correctness, not for high-volume rendered tile delivery.
FAQs
What does PostGIS actually add to Postgres?
It adds spatial types, spatial operators, and spatial indexing so that "where" becomes a first-class, queryable property of a row.
Why doesn't a raw latitude and longitude pair mean anything on its own?
Because the same numbers can describe different real-world locations depending on which coordinate reference system they were measured in, which is why every PostGIS value carries an SRID.
What is an SRID, in plain terms?
It is a numeric identifier for a specific coordinate reference system, telling Postgres exactly how to interpret a shape's coordinates.
Why does PostGIS have two spatial types instead of one?
geometry models the earth as a flat plane for fast local math, while geography models it as a sphere for accurate long-distance math, and each fits a different scale of problem.
How does a spatial index actually make proximity queries fast?
- It first replaces every shape with its bounding box, which is cheap to compare.
- It then runs the exact geometric test only against the small set of candidates that survive that cheap filter.
Why is GiST used instead of a B-tree for spatial data?
B-tree assumes values sort along a single line, but spatial shapes overlap in multiple dimensions with no single natural order, which is exactly the structure GiST is built to index.
Does a spatial index guarantee an exact answer by itself?
No, the index only narrows candidates by bounding box, and the query still needs an exact function like ST_DWithin to confirm the real geometric answer.
What happens if two geometries with different SRIDs are compared directly?
The comparison is either rejected or silently meaningless, which is why transforming to a shared reference system before comparison matters.
When should a team reach for geography instead of geometry?
When distances need to stay accurate across a wide area, such as global GPS radius queries, geography's spherical math avoids the distortion planar geometry introduces at that scale.
Why is PostGIS not usually the system that renders map tiles?
PostGIS is optimized for transactional storage, spatial joins, and correctness, while tile rendering favors a dedicated, cache-friendly pipeline built for that one job.
What is the most common real-world spatial bug?
Mixing coordinate reference systems, such as computing distance on unprojected 4326 geometry and reading the result as meters when it is actually degrees.
Does adding more spatial precision always help query performance?
No, higher-precision or more complex shapes make the bounding-box prefilter less selective and increase index and storage cost, so simplification is often worth it at scale.
Related
- PostGIS Basics - installing the extension and choosing Postgres versus a tile server.
- Geometry vs Geography - the full type and SRID comparison this page only summarizes.
- Spatial Indexes - concrete GiST index creation and query patterns.
- PostGIS Performance - simplification and bounding-box prefilter techniques at scale.
- Extensions Basics - how the extension system PostGIS plugs into actually works.
Stack versions: This page was written for PostGIS 3.5+. It is otherwise conceptual and not tied to a specific PostgreSQL minor version.