akuechler/laravel-geoly
Laravel GeoLy adds geospatial querying to Eloquent, letting you store coordinates and run distance-based searches, radius filters, and nearby lookups directly in your models without extra services.
Architecture fit. laravel-geoly is a trait-plus-Eloquent-scope package: it adds a withinRadius-style query scope to any model carrying latitude/longitude columns. Architecturally this is the lowest-friction shape a Laravel package can take — no service container bindings to reason about, no external geo service, no queue or event surface, and no schema ownership beyond two columns. It computes a bounding-box prefilter in SQL and then applies a haversine distance calculation for exact filtering/ordering. That means it stays entirely inside the application's existing database connection: no PostGIS extension, no Redis GEO, no third-party API, no new network hop on the read path. For a Laravel monolith with moderate geo needs (store locators, "near me" listings, delivery-radius checks, marketplace search), this is a proportionate fit. It is not a fit if geo search is a core product differentiator requiring polygon queries, routing, or sub-100ms p95 at high query volume.
Integration feasibility. High on a technical level, low on a supply-chain level. The code surface is small enough that a competent Laravel engineer can read the whole package in an hour and fork it if needed, so lock-in is negligible — the real cost is the evaluation cost, not the adoption cost. The 2021-04-20 last release and 41 stars are the material findings: at the time of writing this almost certainly predates Laravel 9/10/11 service-provider conventions and PHP 8.2+ deprecations, so the composer.json constraint (illuminate/support, php) will likely block installation on a current stack before any code-level incompatibility surfaces. Budget a half-day spike to confirm whether it installs cleanly or requires a fork with relaxed constraints.
Technical risk. Three buckets:
(latitude, longitude) exists. Without it you get a full table scan with trig functions in the WHERE clause — a query that passes in staging and times out in production.Key questions for the spike.
composer.json constraints on PHP and illuminate/*, and does it install on our target Laravel version without --ignore-platform-reqs?lat/lng columns and index ourselves?Stack fit. Appropriate for Laravel 8-era or earlier applications with MySQL/PostgreSQL and read-heavy, low-to-moderate-QPS geo filtering. Assume it is not supported on our current Laravel version until the spike proves otherwise. It is a poor fit for multi-tenant databases with per-tenant sharding, for read models backed by Elasticsearch/Algolia (those have native geo), or anywhere we already run PostGIS — in those cases the package duplicates capability we already pay for.
Migration path. Two viable routes, decided by the spike:
composer require, add decimal(10,7)/(10,8) columns, backfill coordinates through our existing geocoder in batched jobs, add a composite (latitude, longitude) index, add the trait, and wrap the scope in a repository/service method so the package is callable from exactly one place. That single choke point is the whole point: it makes the eventual build-vs-fork-vs-replace decision a one-file change.composer.json), relax the framework/PHP constraints, add a test suite covering the correctness risks above, and publish it internally. Cost is roughly 1–2 engineer-days including tests — still cheaper than writing haversine logic from scratch, but not by much, which is the honest framing to give stakeholders.Compatibility. Verify against our actual stack matrix rather than the package's declared one: PHP version, Laravel version, and database engine. SQLite-backed test suites are a specific trap — SQLite only exposes RADIANS/COS/SIN when built with math-function support, so a passing CI suite on SQLite does not validate production behaviour on MySQL/PostgreSQL. Run correctness tests against a containerised copy of the production engine.
Sequencing.
Do not sequence this behind a geo-dependent product launch; the dependency's staleness makes it a schedule risk.
Maintenance. Effectively zero upstream maintenance — plan for us to be the maintainers. The upside is that the maintenance burden is small: one trait, one scope, no runtime services. Assign clear internal ownership and pin the version (or the fork's commit SHA) so an accidental composer update cannot silently change query semantics. Add it to the quarterly dependency-review list with a standing "fork is current" check.
Support. No vendor, no SLA, minimal community (41 stars implies few answered issues and little Stack Overflow coverage). Internal documentation is mandatory: unit conventions, the earth-radius constant, supported database engines, and the known antimeridian limitation should live in an ADR, not in someone's head. Expect onboarding engineers to ask "why do we have this tiny unmaintained package?" — the ADR answers that.
Scaling. The bounding-box-plus-index approach scales comfortably to low millions of rows for typical radii, which covers most product needs. It does not scale to full-table geo search: once the bounding box filters a large fraction of the table (very large radius, or a dense urban dataset), you are back to a scan with trig functions in the predicate. It also has no caching layer — callers must add response caching themselves. At high query volume or when geo becomes a discovery surface rather than a filter, the migration target is PostGIS or a search engine with native geo (Meilisearch, Algolia, Elasticsearch), not a bigger version of this package. Design the service-layer wrapper now so that swap stays cheap.
Failure modes. Ranked by likelihood × impact:
Ramp-up. Very low for any Laravel developer: one trait, one scope, roughly an hour to productive use once the ADR and tests exist. The ramp-up cost sits with the first engineer, who must do the evaluation, fork, and test work — estimate 1–2 days. After that the package is invisible infrastructure.
TPM recommendation. Proceed to spike, with the default expectation of adopting the code via an internal fork rather than consuming the upstream release. The package's low score reflects stewardship, not engineering quality, and the blast radius of that poor stewardship is unusually small here because the code is trivially replaceable. Gate full adoption on the benchmark and the correctness tests, and require the service-layer wrapper so the decision remains reversible.
How can I help you explore Laravel packages today?