---
title: The postgis extension
subtitle: Work with geospatial data in Postgres using PostGIS
enableTableOfContents: true
updatedOn: '2025-08-02T10:33:29.247Z'
---
The `postgis` extension provides support for spatial data - coordinates, maps and polygons, encompassing geographical and location-based information. It introduces new data types, functions, and operators to manage and analyze spatial data effectively.
This guide introduces you to the `postgis` extension - how to enable it, store and query spatial data, and perform geospatial analysis with real-world examples. Geospatial data is crucial in fields like urban planning, environmental science, and logistics.
PostGIS is an open-source extension for Postgres that can be installed on any Neon Project using the instructions below. Detailed installation instructions and compatibility information can be found at [PostGIS Documentation](https://postgis.net/documentation/).
For information about PostGIS-related extensions, including `pgrouting`, H3_PostGIS, PostGIS SFCGAL, and PostGIS Tiger Geocoder, see [PostGIG-related extensions](/docs/extensions/postgis-related-extensions).
**Version availability:**
Please refer to the [list of all extensions](/docs/extensions/pg-extensions) available in Neon for up-to-date information.
## Enable the `postgis` extension
You can enable the extension by running the following `CREATE EXTENSION` statement in the Neon **SQL Editor** or from a client such as `psql` that is connected to Neon.
```sql
CREATE EXTENSION IF NOT EXISTS postgis;
```
For information about using the Neon SQL Editor, see [Query with Neon's SQL Editor](/docs/get-started/query-with-neon-sql-editor). For information about using the `psql` client with Neon, see [Connect with psql](/docs/connect/query-with-psql-editor).
## Example usage
**Create a table with spatial data**
Suppose you're managing a city's public transportation system. You can create a table to store the locations of bus stops.
```sql
CREATE TABLE bus_stops (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
location GEOGRAPHY(Point)
);
```
Here, the location column is of type `GEOGRAPHY(Point)`, which is a spatial data type provided by the `postgis` extension and used to store points on the Earth's surface.
**Inserting data**
Data can be inserted into the table using regular `INSERT` statements.
```sql
INSERT INTO bus_stops (name, location)
VALUES
('Main St & 3rd Ave', ST_Point(-73.935242, 40.730610)),
('Elm St & 5th Ave', ST_Point(-73.991070, 40.730824));
```
The `ST_Point` function is used to create a point from the specified longitude and latitude.
**Querying spatial data**
Now, we can perform spatial queries using the built-in functions provided by `PostGIS`. For example, below we try to find points within a certain distance from a reference.
Query:
```sql
SELECT name FROM bus_stops
WHERE ST_DWithin(location, ST_Point(-73.95, 40.7305)::GEOGRAPHY, 2000);
```
This query returns the following:
```text
| name |
|--------------------|
| Main St & 3rd Ave |
```
The `ST_DWithin` function returns true if the distance between two points is less than or equal to the specified distance (when used with the `GEOGRAPHY` type, the unit is meters).
## Spatial data types
PostGIS extends Postgres data types to handle spatial data. The primary spatial types are:
- **GEOMETRY**: A flexible type for spatial data, supporting various shapes. It models shapes in the cartesian coordinate plane. Each `GEOMETRY` value is also associated with a spatial reference system (SRS), which defines the coordinate system and units of measurement.
- **GEOGRAPHY**: Specifically designed for large-scale spatial operations on the Earth's surface, factoring in the Earth's curvature. The coordinates for a `GEOGRAPHY` shape are specified in degrees of longitude and latitude.
The actual shapes are stored as a set of coordinates. For example, a point is stored as a pair of coordinates, a line as a set of points, and a polygon as a set of lines.
## Longer example
PostGIS provides a number of other functions for spatial analysis - area, distance, intersection, and more. To illustrate, we'll create dataset representing a small set of landmarks and roads in a fictional city and run spatial queries on it.
**Creating the test dataset**
```sql
CREATE TABLE landmarks (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
location GEOMETRY(Point)
);
CREATE TABLE roads (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
path GEOMETRY(LineString)
);
INSERT INTO landmarks (name, location)
VALUES
('Park', ST_Point(100, 200)),
('Museum', ST_Point(200, 300)),
('Library', ST_Point(300, 200));
INSERT INTO roads (name, path)
VALUES
('Main Street', ST_MakeLine(ST_Point(100, 200), ST_Point(200, 300))),
('Second Street', ST_MakeLine(ST_Point(200, 300), ST_Point(300, 200)));
```
**Nearest landmark to a given point**
Finding the nearest places to a given point is a common spatial query. We can use the `ST_Distance` function to find the distance between two points and order the results by distance.
```sql
SELECT name, ST_Distance(location, ST_GeomFromText('POINT(150 250)')) AS distance
FROM landmarks
ORDER BY distance
LIMIT 1;
```
This query returns the following:
```text
| name | distance |
|--------|----------|
| Park | 70.7107 |
```
**Intersection of Roads**
We can use the `ST_Intersects` function to find if two roads intersect. To ensure we don't get duplicate pairs of roads, we filter out pairs where the first road has a higher `id` than the second road.
```sql
SELECT a.name, b.name
FROM roads a AS name_A, roads b AS name_B
WHERE a.id < b.id AND ST_Intersects(a.path, b.path);
```
This query returns the following:
```text
| name_A | name_B |
|----------------|----------------|
| Main Street | Second Street |
```
**Buffer zone around a landmark**
Say, the municipal council wants to create a buffer zone of 50 units around landmarks and check which roads intersect these zones. `ST_Buffer` computes an area around the given point with the specified radius.
```sql
SELECT l.name AS landmark, r.name AS road
FROM landmarks l, roads r
WHERE ST_Intersects(r.path, ST_Buffer(l.location, 50));
```
This query returns the following:
```text
| landmark | road |
|----------|---------------|
| Park | Main Street |
| Museum | Main Street |
| Museum | Second Street |
| Library | Second Street |
```
**Line of Sight Between Landmarks**
To check if there's a direct line of sight (no roads intersecting) between two landmarks, we can combine two `postgis` functions.
```sql
SELECT
'No direct line of sight' AS info
FROM
landmarks l1, landmarks l2, roads r
WHERE
l1.name = 'Park' AND l2.name = 'Library' AND
ST_Intersects(ST_MakeLine(l1.location, l2.location), r.path)
LIMIT 1;
```
This query returns the following:
```text
| info |
|--------------------------|
| No direct line of sight |
```
This tells us there's no direct line of sight between the Park and the Library.
## Performance considerations
When working with PostGIS, thinking about performance is crucial, especially when dealing with large datasets or complex spatial queries.
### Indexing
**GIST** (Generalized Search Tree) is the default spatial index in PostGIS. GiST indexes are well-suited for multidimensional data, like points, lines, and polygons. It can significantly improve query performance, especially for spatial search operations and joins.
```sql
CREATE INDEX spatial_index_name ON landmarks USING GIST(location);
```
### Query optimization
- **Unnecessary Casting**: `GEOMETRY` and `GEOGRAPHY` are the two primary data types in `postgis`, and a lot of functions are overloaded to work with both. However, casting between the two types can be expensive, so it's best to store data in the more frequently used type.
- **Use Appropriate Precision**: Reducing the precision of coordinates can often improve performance without significantly impacting the results.
## Conclusion
These examples provide a quick introduction to handling and analyzing spatial data in PostgresQL. We saw how to create tables with spatial data, insert data, and perform spatial queries using the `postgis` extension. It offers a powerful set of tools, with functions for calculating distances, identifying spatial relationships, and aggregating spatial data.
## Resources
- [PostGIS Documentation](https://postgis.net/documentation)
- [PostGIS Intro Workshop](https://postgis.net/workshops/postgis-intro/)