gabelbart/nova-geolocation-field
A Laravel Nova geolocation field that adds an interactive map picker to your forms. Search for an address, drop a pin, and save latitude and longitude coordinates directly to your model.
Vet it before you install it. This package has essentially no adoption signal — zero stars listed, zero dependents, and it lives on GitLab rather than Packagist's usual ecosystem. Before committing it to a project, read its composer.json and confirm:
laravel/nova constraint. Nova 3 fields (Vue 2) and Nova 4/5 fields (Vue 3) are not interchangeable; a Nova 3 component will typically fail to boot on Nova 4+.gabelbart/* dependencies.If it targets your Nova major, proceed. If not, stop here and budget an afternoon to fork it.
Install and publish:
composer require gabelbart/nova-geolocation-field
php artisan vendor:publish --provider="Gabelbart\NovaGeolocationField\FieldServiceProvider"
The publish step is what surfaces the config file (API key, default center, default zoom) and copies compiled assets into public/vendor. Confirm the exact provider namespace from the README — that's the one string you should never guess.
Create the storage first. Geolocation fields expect either two decimal columns or one JSON/point column. Two columns is the right default:
$table->decimal('latitude', 10, 7)->nullable();
$table->decimal('longitude', 10, 7)->nullable();
First use case — prove the round trip. Add the field to a resource form, click a point on the map, save, reload the edit screen, and confirm the marker returns where you left it:
use Gabelbart\NovaGeolocationField\GeolocationField;
GeolocationField::make('Location', 'location')
->latitude('latitude')
->longitude('longitude');
Adjust the fluent method names to whatever the README documents — the two-column binding convention is the part that matters, not the exact API.
Prefer two real columns over a serialized blob. Keeping latitude/longitude as decimal columns means you can sort, filter, and hand the data to PostGIS or a bounding-box query later. A single JSON column looks tidier in the resource but locks you out of every SQL-level geo operation.
Pair the map with a text address field. The normal workflow is an address input plus the map picker: geocode the address server-side (Google Geocoding, Mapbox, Nominatim) in a saving hook or fillUsing, and fall back to manual map placement when geocoding returns nothing. Reverse-geocoding on every drag event is too chatty — do it on marker drop only, debounced.
Normalize at the model boundary. Whatever internal shape the field posts, flatten it in a mutator so the rest of the app never sees the component's payload format:
public function setLocationAttribute($value)
{
$this->attributes['latitude'] = $value['lat'] ?? null;
$this->attributes['longitude'] = $value['lng'] ?? null;
}
Forms only. Maps have no place in an index table. Use ->onlyOnForms() (or ->hideFromIndex()) and render a static value or "View on map" link in the index and detail views. If you genuinely want a map on detail, use a ->readonly() instance rather than inventing a second component.
One field instance per coordinate pair. Nova resolves fields by attribute name; two map fields bound to the same latitude/longitude will fight over the payload on save. For "pickup" and "dropoff," use four columns and two separate field instances.
Skip it in actions and tools. Nova actions run server-side, so the field is irrelevant there. Set the model attributes directly and let the field render the result — do not try to drive the Vue component programmatically.
The API key ships to the browser. Anything published into the config ends up in the compiled bundle and is visible to every user. Restrict the key by HTTP referrer in the cloud console, enable only the APIs you actually use (Maps JavaScript, Geocoding, Places), and set a budget alert. This is not optional on a key that reaches production.
0,0 is not "empty." Null Island is a real coordinate. If the component writes 0.0 for an untouched field, you get phantom data points off the coast of Africa. Check what a fresh, never-clicked field submits and add a guard if it silently writes zeros.
Add bounds validation yourself. Nova's ->rules() has no idea this is geographic data. Add between:-90,90 for latitude and between:-180,180 for longitude — a swapped lat/lng is easy to save and miserable to notice.
Version drift is the real risk. With zero dependents, nobody else is filing the "breaks on Nova 5" issue for you. Pin the exact version, and before any Nova upgrade, confirm the Vue component still compiles. The escape hatch is to copy the field into nova-components/ and maintain it yourself — these are usually a few hundred lines wrapping a map library, so it's a contained amount of work.
Stale assets are the default failure mode. Blank panels, old component versions, and mysterious JS errors in Nova fields are almost always an unpublished asset. Run php artisan nova:publish, clear config and view caches, then hard-reload. Check the browser console first: a 404 on the field's JS or a missing Nova.booting registration tells you instantly whether it's a build problem or a data problem.
Don't trust sortable() or filterable(). Even if advertised, sorting a map field is meaningless. Write a separate proximity/scoping filter if you need distance queries.
Extension points worth checking in the config: default center and zoom, provider choice (Google vs Leaflet/OSM), and whether the search box calls a geocoding service. If the provider is hard-coded, prefer a config override plus an edited copy of the published Vue component over a fork of the whole package.
Debugging order: (1) browser console — did the field's JS load at all? (2) API key restrictions and enabled APIs, (3) the save request payload — is the field name present and shaped as the mutator expects? (4) the database — are the columns nullable and correctly typed? Most "it won't save" reports are a field-name/attribute mismatch or decimal precision quietly truncating the coordinates.
How can I help you explore Laravel packages today?