PUBLISHED | 5 min read

Build a golf course locator with Mapbox and PostGIS

Last edited: Sep 11, 2026 - Published Sep 11, 2026
Listen
--:--
Build a golf course locator with Mapbox and PostGIS

If you're building a golf app, one of the first features users expect is a way to find courses near them. But a simple list sorted by distance won't cut it when your database grows to thousands of courses. You need a system that can answer "what's the nearest course to this point?" in milliseconds, even with millions of rows. That's where PostGIS and Mapbox come in.

PostGIS, the spatial extension for PostgreSQL, gives you the database power to run fast nearest-neighbor queries. Mapbox provides the interactive map layer that turns that data into a visual experience. Together, they form the backbone of a production-ready golf course locator.

Quick Quiz

Which operator does PostGIS use for index-assisted nearest-neighbor searches?

Select one answer.

Why PostGIS for course data

PostGIS stores spatial features as geometry or geography types and uses GiST indexes to accelerate spatial queries. Without an index, a nearest-neighbor search on a large table would require scanning every row and computing distances—a process that can take seconds on a dataset of just a few million features. With a GiST index, PostGIS can return the nearest courses almost instantly.

The key is the <-> operator, which PostGIS uses for "order by distance" queries. This operator leverages the R-tree spatial index to find the N nearest features without computing exact distances for every row. For example, to find the 10 courses nearest to a given point, you'd write:

SELECT name, geom <-> ST_SetSRID(ST_MakePoint(-118.29, 36.58), 4326) AS dist
FROM courses
ORDER BY dist
LIMIT 10;

This query uses the index to return results in milliseconds, even on tables with millions of rows. The PostGIS workshop notes that with an "order by distance" operator in place, a nearest neighbor query can return the N nearest features just by adding an ordering and limiting the result set. For even better performance, you can combine the <-> operator with a bounding box filter (&&) to narrow the search area first, then refine with exact distance calculations.

Setting up your spatial database

Start by enabling PostGIS in your PostgreSQL database:

CREATE EXTENSION postgis;

Then create a table for your courses. You'll want a geometry column with SRID 4326 (WGS84) for global coordinates:

CREATE TABLE courses (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  geom GEOMETRY(POINT, 4326)
);

CREATE INDEX idx_courses_geom ON courses USING GIST(geom);

The GiST index is crucial—without it, your nearest-neighbor queries will degrade to full table scans. Always verify your query plan with EXPLAIN to ensure the index is being used.

Loading course data

You can populate your table with data from a geodata API like Golfbert, which provides detailed hole polygons and vector coordinates for thousands of US courses. If you're starting from scratch, you can also trace satellite imagery in a tool like QGIS to create your own course polygons—an entire course layout can be mapped in under 30 minutes. For a locator, you'll typically need at least the course's centroid or a representative point, plus its name and ID.

Building the Mapbox front end

Once your database is ready, you'll expose an API endpoint that accepts a user's latitude and longitude and returns the nearest courses. Your backend query might look like:

SELECT id, name, ST_AsGeoJSON(geom) AS geojson,
       ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint($1, $2), 4326)::geography) AS dist_m
FROM courses
ORDER BY geom <-> ST_SetSRID(ST_MakePoint($1, $2), 4326)
LIMIT 10;

On the front end, use Mapbox GL JS to render the results. You'll add a source with the GeoJSON response and a layer to display course markers. When the user pans or zooms, you can re-query the API and update the source. For a smoother experience, consider using Mapbox's queryRenderedFeatures to filter markers by the current viewport.

Performance tips

  • Always use GiST indexes on geometry columns. This is the single most important factor for query speed.
  • Simplify geometries for display. Use ST_Simplify to reduce polygon complexity when you don't need high precision, which speeds up rendering and queries.
  • Use <-> for nearest-neighbor searches instead of ST_Distance in the ORDER BY clause. The <-> operator uses bounding boxes and the index, while ST_Distance forces a full scan.
  • Filter with && first to limit the search area, then refine with exact functions. This two-step approach avoids heavy computations on distant features.
  • Monitor query plans with EXPLAIN ANALYZE to ensure your queries are using the index. If you see a sequential scan, your query may need adjustment.

Putting it all together

A typical request flow looks like this:

  1. User opens your app and grants location access.
  2. Your front end sends the user's coordinates to your API.
  3. Your API runs a PostGIS nearest-neighbor query to fetch the 10 closest courses.
  4. The API returns GeoJSON to the front end.
  5. Mapbox renders the courses as markers, with a popup showing the name and distance.

This architecture scales from a small local app to a national or global service. PostGIS handles the heavy lifting, and Mapbox provides the interactive map that users love.

Quiz: Test your knowledge

Which operator does PostGIS use for index-assisted nearest-neighbor searches?

  • <->
  • ST_Distance
  • ST_Intersects

How the Featured Expert Can Help

If you need accurate, developer-friendly golf course geodata, Golfbert provides a geodata API with detailed hole polygons, greens, fairways, and hazards for thousands of US courses. Their documentation and pricing plans are designed for developers building golf applications, making it easy to integrate reliable course data into your PostGIS database and Mapbox front end.

Back to homepage