April 13, 2026

Stop Using the Haversine Formula: Scaling Geospatial Queries with Laravel and PostGIS

By Paresh Prajapati • Lead Architect

Stop Using the Haversine Formula: Scaling Geospatial Queries with Laravel and PostGIS

The Location Bottleneck in SaaS

Whether you are building an AgriTech platform mapping thousands of farm boundaries or a B2B logistics dashboard tracking active assets, location data is foundational. Historically, developers handle proximity searches ("find all farms within a 50km radius") by storing standard latitude and longitude floats in the database and calculating the distance on the fly using the Haversine formula.

For a few hundred records, this works. But as your platform scales to millions of data points, running heavy trigonometric math on every single row during a query will completely paralyze your database. The CPU spikes, queries time out, and your API grinds to a halt. At Smart Tech Devs, we bypass this bottleneck entirely by architecting our PostgreSQL databases with PostGIS.

Enter PostGIS: Enterprise Geospatial Architecture

PostGIS is an extension for PostgreSQL that turns it into a spatial database. Instead of treating coordinates as raw numbers, it introduces native Geometry and Geography data types. More importantly, it allows you to utilize Spatial Indexes (GiST), meaning PostgreSQL can search physical space as efficiently as it searches standard text or integers.

Step 1: The Laravel Migration

To implement this in Laravel, we first ensure the PostGIS extension is enabled on our server, and then we define a spatial column in our migration.


use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;

class CreateFarmsTable extends Migration
{
    public function up(): void
    {
        // 1. Enable the PostGIS extension on the PostgreSQL database
        DB::statement('CREATE EXTENSION IF NOT EXISTS postgis;');

        Schema::create('farms', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->foreignId('tenant_id')->constrained();
            
            // 2. Define a spatial column. We use 'geography' for standard GPS coordinates 
            // because it automatically handles the curvature of the Earth for accurate distances.
            $table->geography('location', subtype: 'point', srid: 4326);
            $table->timestamps();
        });

        // 3. Create a spatial GiST index for lightning-fast lookups
        DB::statement('CREATE INDEX farms_location_gist ON farms USING GIST (location);');
    }
}

Step 2: Lightning-Fast Proximity Queries

Now, instead of pulling all records into PHP to calculate distances, we let PostgreSQL's spatial engine do the heavy lifting using the ST_DWithin function. This leverages our GiST index to return results in milliseconds.


namespace App\Repositories;

use App\Models\Farm;
use Illuminate\Support\Facades\DB;

class SpatialRepository
{
    /**
     * Find all farms within a specific radius of a target point.
     */
    public function getFarmsWithinRadius(float $lat, float $lng, int $radiusInMeters)
    {
        // Create a spatial point from the user's coordinates
        $targetPoint = "ST_SetSRID(ST_MakePoint({$lng}, {$lat}), 4326)";

        return Farm::query()
            ->whereRaw("ST_DWithin(location, {$targetPoint}, ?)", [$radiusInMeters])
            // Optionally, select the exact distance to display to the user
            ->select('*')
            ->selectRaw("ST_Distance(location, {$targetPoint}) AS distance_meters")
            ->orderBy('distance_meters', 'asc')
            ->get();
    }
}

The Engineering ROI

By shifting to PostGIS, you transform an O(N) full-table scan operation into an O(log N) indexed search. This architecture allows platforms to scale spatial data infinitely, handling massive agricultural maps, weather tracking coordinates, and fleet logistics without breaking a sweat. Stop doing math in your application layer; let your database handle the geometry.

Paresh Prajapati
Lead Architect, Smart Tech Devs