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.
Search across all documentation pages
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.
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.
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.
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 |
It adds spatial types, spatial operators, and spatial indexing so that "where" becomes a first-class, queryable property of a row.
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.
It is a numeric identifier for a specific coordinate reference system, telling Postgres exactly how to interpret a shape's coordinates.
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.
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.
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.
The comparison is either rejected or silently meaningless, which is why transforming to a shared reference system before comparison matters.
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.
PostGIS is optimized for transactional storage, spatial joins, and correctness, while tile rendering favors a dedicated, cache-friendly pipeline built for that one job.
Mixing coordinate reference systems, such as computing distance on unprojected 4326 geometry and reading the result as meters when it is actually degrees.
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.
Stack versions: This page was written for PostGIS 3.5+. It is otherwise conceptual and not tied to a specific PostgreSQL minor version.
Reviewed by Chris St. John·Last updated Jul 15, 2026