Open-source project
geocoder-php/GeocoderLaravel avatar
geocoder-php/GeocoderLaravel

GeocoderLaravel: geocoding providers wired into Laravel

Geocoder service provider for Laravel

754 stars108 forksPHPMIT

At a glance

What is it?
GeocoderLaravel is the Laravel service provider for the Geocoder PHP library, adding a resolved geocoder instance, a configurable cache and the upstream provider chain to any Laravel application. Its most interesting work in version 13 is negotiating Laravel's new serializable classes restriction so cached results keep working.
Who is it for?
GeocoderLaravel suits a Laravel application that needs forward or reverse geocoding without writing the provider plumbing by hand, since the chain, the cache and the config file are all provided. It does not suit an application on Laravel 10 or earlier, since version 13 requires Laravel 11 or above and PHP 8.2.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 123 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the package wraps and what it adds

This package allows you to use Geocoder in Laravel. It is the Laravel service provider for the upstream Geocoder PHP library, and its job is to give a Laravel application a resolved geocoder instance, a config file for the provider chain, and a cache wired to the framework's own cache system.

The requirements are PHP 8.2 or above and Laravel 11.0 or above, and the version scheme is worth understanding before you install. Starting with 13.0.0 the package's major version tracks the highest supported Laravel major version rather than the upstream Geocoder PHP version. So 13.x supports Laravel 11, 12 and 13, the next major will be 14.x when Laravel 14 ships, and so on. The README is explicit that the previous tag was 5.0.0 and that the jump to 13.0.0 reflects the new scheme rather than nine intermediate releases.

Two warnings sit at the top of the README. Version 13.0.0 is a backwards-compatibility-breaking update, and the upgrading section is called out specifically for the new default HTTP adapter. And if you still use Laravel 4, the 0.4.x branch is the one to look at.

The home page is geocoder-php.org/GeocoderLaravel, the repository is under the geocoder-php organisation, and the packagist package name is toin0u/geocoder-laravel, which is what you put in your composer command.

Installation and the cache-clearing composer hooks

The install is a composer require.

bash
composer require toin0u/geocoder-laravel

On Laravel 5.5 the package is auto-discovered and that step can be skipped. If you are on an old release, you find the providers array key in config/app.php and register the Geocoder Service Provider.

php
// 'providers' => [
    Geocoder\Laravel\Providers\GeocoderService::class,
// ];

The third step is optional and the README recommends it. Adding two composer hooks clears the application cache after an update and after an install, which prevents stale caches when the package is upgraded or updated, in both the live and the development environment.

json
"post-update-cmd": [
    "@php artisan cache:clear",
],
"post-install-cmd": [
    "@php artisan cache:clear",
]

That recommendation matters more than it looks, because the package caches geocoding results and a cached result from an old provider version can differ from what the new code would return. The hooks are the package author's way of avoiding a class of confusing bug rather than a matter of tidiness.

Configuring the dedicated cache store

The recommended configuration is a separate Redis store for geocoding, and it takes three edits.

First, a Redis connection entry in config/database.php, under the redis key, with a name of your choosing.

php
"geocode-cache" => [ // choose an appropriate name
    'host' => env('REDIS_HOST', '192.168.10.10'),
    'password' => env('REDIS_PASSWORD', null),
    'port' => env('REDIS_PORT', 6379),
    'database' => 1, // be sure this number differs from your other redis databases

The comment on the database number is the detail to notice. A separate Redis database is the simplest way to isolate the geocode cache so a flush of one does not take the other with it, and the number has to differ from the ones your other stores use.

Second, a cache store entry in config/cache.php pointing at that connection.

php
"geocode" => [
    'driver' => 'redis',
    'connection' => 'geocode-cache',
],

Third, the geocoder config file names the store.

php
"cache" => [
    "store" => "geocode",

Caching can also be turned off for a single query, which is the escape hatch when you want a fresh result for a request that matters.

php
$results = app("geocoder")
    ->doNotCache()
    ->geocode('Los Angeles, CA')
    ->get();

The README also flags the upgrade path. If you are upgrading and have previously published the geocoder config file, you need to add the cache-duration variable, otherwise caching is disabled because it defaults to a 0 cache duration. The default cache duration the config file provides is 999999999 seconds, which is effectively forever.

The Laravel 13 serializable classes problem

This is the part of the README worth reading twice, because it is a case where a package deliberately relaxes a framework security control.

Laravel 13 introduced cache.serializable_classes as a security hardening measure, defaulting to false to block deserialization of arbitrary PHP objects from the cache. This package stores Collections of Address objects in the cache, which would silently break caching under the new default.

The package's answer is to scan the installed Geocoder vendor directories at boot and merge every model class it finds into the application's cache.serializable_classes allow-list. Whatever providers you have installed under vendor/geocoder-php/* are covered automatically, so there is no curated list to go stale.

The README states the security implication plainly. The package narrowly relaxes Laravel 13's hardening for the geocoder model classes installed in the vendor directory, and other PHP objects you store in the cache remain blocked unless you explicitly allow them. The blast radius is bounded to classes you have already deliberately installed through composer.

There is an opt-out. Setting auto_register_serializable_classes to false in config/geocoder.php means the package will not touch the allow-list at all.

php
'cache' => [
    // ...
    'auto_register_serializable_classes' => false,
],

With that set, the README gives two reasonable paths. Either you manage the allow-list yourself, adding the geocoder model classes to the serializable_classes list in config/cache.php directly, which keeps caching working under explicit control and is the choice if you want to audit exactly which PHP objects your application allows to deserialize. Or you disable caching for geocoder queries, either by calling doNotCache() on each query or by setting cache.duration to 0, which is the choice if you do not want to maintain the list and can absorb the per-request API cost.

The README warns that doing neither under Laravel 13 could cause __PHP_Incomplete_Class corruption on cached results, which is a specific and memorable symptom of a cached object that failed to unserialize.

Provider chains and configuration caveats

The configuration section calls out two things that trip people up.

The first is language and region values. Pay special attention to them, the README says, and the GoogleMaps provider is the example: it uses TLDs for region values and its own scheme for language values, with a link to the Google documentation for the language list. The general rule is that the region and language values are provider specific rather than universal, so a config that works with one provider can silently behave differently with another.

The second is the GoogleMaps provider and API keys. If you are using an API key, you must also set HTTPS to true, and the README's advice is to leave it true always unless there is a specific requirement not to.

By default, the configuration specifies a Chain provider containing the GoogleMaps provider for addresses as well as reverse lookups with latitude and longitude, and the GeoIP provider for IP addresses. The first provider to return a result is returned and subsequent providers are not executed, which is the behaviour that makes a chain worth configuring: the second provider is the fallback, not an addition, so the ordering decides which provider actually bills you.

The default config file is described as kept lean, with only those two providers, and the Geocoder documentation is the reference for the full list of available adapters and providers.

Where GeocoderLaravel is the wrong choice

The first limitation is the version floor. Version 13 needs Laravel 11 or above and PHP 8.2, and the package's own major version now tracks the Laravel version, which means every Laravel release forces a package release and a major version bump in the semver sense. A team on Laravel 10 is on the previous package line, and a team that upgrades Laravel every year will be upgrading this package every year too, with a configuration file to check because the cache-duration variable and the allow-list behaviour both changed.

The second is the cache default. The default cache duration of 999999999 seconds is effectively forever, and a geocode result cached indefinitely will outlive whatever the provider was describing. A new road, a renamed venue, a corrected postcode, none of it reaches a cached result. The doNotCache() call exists for that, but it has to be remembered at the call site rather than configured once.

The third is the cache hardening trade-off, and it deserves more attention than the README gives it. The automatic registration of geocoder model classes in cache.serializable_classes means the allow-list is computed at boot from whatever is in the vendor directory, so the set of deserialisable classes changes with a composer update rather than with a config change. The blast radius is bounded to classes you installed deliberately, but it is bounded by directory contents rather than by a list someone reviewed, and a team with a strict deserialisation policy should take the opt-out and maintain the list by hand.

The fourth is the provider dependency. The package does not geocode anything itself, it delegates to the providers, and GoogleMaps in particular needs a key and an account, so the cost model is the provider's and the free tier's limits are your real constraint. The default chain also means your first provider is the one that gets billed, and changing the order changes which one that is.

The fifth is the geocoding quality itself. The package turns a string into coordinates and back, and the accuracy of that is the provider's, not the package's, so a business that depends on precise addresses will spend its effort on the provider configuration and on the country and language parameters rather than on this layer.

Licence, maintenance and the cost of a provider wrapper

The project is under the MIT licence, with the LICENSE file at the root of the repository, and it ships the usual quality tooling: a .php-codesniffer directory with a phpcs.xml and a phpmd.xml, a phpunit.xml for the tests, a pint.json for formatting, a testbench.yaml for the Orchestra testbench harness, and a CHANGELOG.md.

The repository is not archived and the last push was on 2026-06-23, the same day as the 13.2.2 release, so the package is actively maintained. The release history shows a steady stream: 13.2.2 in June 2026, 13.2.1 in May and 13.2.0 in May, and the 13.2.0 release note is a cache compatibility fix for Laravel 13, which is the subject of the previous section.

The cost of the package is one composer dependency and one config file. The cost of the setup is the three-step Redis configuration, which is the part people get wrong, since the connection name, the cache store name and the geocoder config key all have to agree.

What the package genuinely saves is the plumbing. Without it, a Laravel application that wants a geocoder has to resolve the upstream library through the container, decide on a cache, wire the provider chain and handle the container's own serialisation rules. The service provider does the resolution, the config file does the chain, and the serialisable classes handling removes the one failure that a Laravel 13 upgrade would otherwise introduce silently.

The upstream project is at geocoder-php.org, and the README points there for the list of available adapters and providers, which is the right place to look when the question is which provider to add next rather than how to install this one.

Editorial conclusion

GeocoderLaravel suits a Laravel application that needs forward or reverse geocoding without writing the provider plumbing by hand, since the chain, the cache and the config file are all provided. It does not suit an application on Laravel 10 or earlier, since version 13 requires Laravel 11 or above and PHP 8.2. Read the serializable classes section before you upgrade, because the automatic allow-list registration is a deliberate relaxation of Laravel's cache hardening rather than a transparent fix.

Frequently asked questions

How do I install GeocoderLaravel?

Run composer require toin0u/geocoder-laravel. On Laravel 5.5 the package is auto-discovered, and on older versions you register Geocoder\Laravel\Providers\GeocoderService in the providers array of config/app.php. The package requires PHP 8.2 or above and Laravel 11 or above.

What changed in GeocoderLaravel 13.0.0?

It is a backwards-compatibility-breaking update with a new default HTTP adapter, and the package's major version now tracks the highest supported Laravel major version instead of the upstream Geocoder PHP version. The previous tag was 5.0.0, so the jump to 13.0.0 reflects the new scheme rather than nine intermediate releases.

Why does caching break under Laravel 13?

Laravel 13 added cache.serializable_classes defaulting to false, which blocks deserialising arbitrary PHP objects from the cache, and the package stores Collections of Address objects there. To keep caching working the package scans the installed Geocoder vendor directories at boot and merges those model classes into the allow-list, and doing neither that nor an explicit opt-out can cause __PHP_Incomplete_Class corruption on cached results.

How do I disable the cache for a single geocoding query?

Call the doNotCache method on the geocoder instance before making the query, for example app("geocoder")->doNotCache()->geocode('Los Angeles, CA')->get(). The alternative is setting cache.duration to 0 in config/geocoder.php, which disables caching for every query.

Official sources

  1. geocoder-php/GeocoderLaravel on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/geocoder-php-geocoderlaravel.svg)](https://hysenlabs.com/projects/geocoder-php-geocoderlaravel)

Was this useful?