farzai/geonames
Laravel package for working with GeoNames data such as countries, cities, timezones and currencies. Provides a simple, expressive API backed by a local database, so you can query geographic data offline without relying on external services or API limits. Easy to install and integrate.
Architecture fit. The 3.0 rewrite converts the package from a network-dependent data fetcher into an offline, snapshot-backed reference-data layer. That is a materially better fit for production Laravel applications: runtime no longer depends on outbound HTTP to GeoNames or on a transport abstraction, and the read path is ordinary Eloquent against locally seeded tables. The removal of farzai/transport, symfony/http-client, symfony/console, psr/log, and ext-zip shrinks the transitive dependency surface and the container/PHP-extension requirements — a net positive for audit and platform-standardisation reviews.
Integration feasibility. The Laravel surface is conventional and low-friction: publishable migrations, a seeder, config, validation rules, and Eloquent casts. Explicit test coverage claims across SQLite, Postgres 16, MySQL 8.4, and MariaDB 10.2/11.8 cover the large majority of our estate, which de-risks the "works on my machine" class of failures. The new domain API (country(), admin1(), admin2(), cities(), city(), postalCodes(), search(), nearest()) is a clean, intention-revealing facade that replaces whatever ad-hoc querying teams built on 2.x.
Technical risk.
data.farzai.com, a third-party (individual-maintainer) host, pinned and sha256-verified. Integrity is addressed; availability and long-term persistence are not. There is no runtime fallback by design, so a missing or withdrawn snapshot blocks new environments and disaster recovery.--feature-class are gone, and PHP 8.3+ is now a floor. Any team relying on export-to-Mongo or on the previous feature-class filtering has no in-package replacement.search()/nearest() performance are unproven at our data volumes.Key questions.
data.farzai.com contractually or operationally durable enough to sit in our DR path, or do we mirror snapshots internally?nearest() require a spatial index or does it do a bounding-box scan — and what is the p95 at our scale?--feature-class?Stack fit. Strong for Laravel 10/11-era applications on PHP 8.3+ and any of the four supported databases. It is a reference-data package, not a general geocoding service — no external API calls, no SDK, no queue worker. That makes it easy to reason about in reviews and trivial to run in air-gapped or restricted-egress environments, provided the snapshot is fetched ahead of time.
Migration path. UPGRADING.md is the entry point and should be treated as required reading, not optional. The realistic path is: (1) inventory every call site touching the 2.x downloader/converter API, including scheduled jobs and any Mongo export; (2) confirm the replacement surface exists for each — for Mongo, it does not, so decide whether to drop the export or rebuild it downstream; (3) stand up a clean environment, fetch the pinned snapshot, publish migrations and config, seed; (4) diff the resulting data against the current 2.x-derived tables for the entity types that matter; (5) cut over reads behind the facade.
Compatibility. The PHP 8.3 floor is the most likely blocker and should be checked first — it invalidates the package for any service still on 8.1/8.2 and may force a coordinated runtime upgrade. Database compatibility is explicitly validated and should not need its own spike. Note that the removal of ext-zip is a relaxation, while the removed converters are the constraint; don't conflate the two when scoping.
Sequencing. Do the snapshot fetch and seed in a non-production environment first, because seeding is the slowest and most resource-hungry step and will define the maintenance-window requirement. Land schema and seed as a discrete change before switching application reads, so a seeding failure does not present as an application outage. Convert read paths facade-by-facade. Keep 2.x code paths behind a flag until the data diff is clean. Publish the attribution notice in the same release as the cutover.
Maintenance. Ongoing cost is low but non-zero and recurring: someone must watch upstream GeoNames changes, re-pin the snapshot, re-verify the hash, and re-seed. This is a calendar-driven task that will be forgotten without an owner — assign it explicitly. Dependency maintenance improves, since the outbound HTTP and console dependencies are gone.
Support. The support surface shifts from "why did the download fail" to "why did the seed fail" and "why is this city missing" — the latter being a data-freshness question answered by the pinned snapshot version. First-line support needs to know the snapshot version in use per environment; expose it in a health check or an artisan command output.
Scaling. Read scaling is standard Eloquent: replica-friendly, cache-friendly, no external latency. The pressure points are write-side and one-off — migration time, seed time, index build time, and disk. search() and nearest() are the read paths to benchmark; geo queries are where an unindexed implementation degrades non-linearly. Plan for per-environment database growth from reference tables that previously lived behind an API call.
Failure modes.
Ramp-up. Modest for any Laravel developer: the facade and Eloquent casts follow framework conventions, so the learning curve is mostly the new method names and the read-only constraint. The real ramp-up cost is operational rather than developer-facing — establishing the fetch/seed/re-pin runbook, the internal snapshot mirror, and the attribution and freshness checks. Budget roughly a day of engineering per consuming service for the 2.x cutover, plus a shared one-time investment in the mirror and runbook.
How can I help you explore Laravel packages today?