Lesson 4 — Coordinates and the lat/lng convention
This is a short lesson about a specific footgun: the order of coordinates when you write them in code. Almost every developer working with maps loses an hour to this at some point. It’s worth spending 15 minutes here so you don’t.
Two conventions exist, both legitimate, and they don’t agree. Different tools, libraries, and data sources pick one or the other, and there’s no consensus. The Vera gem makes a specific choice — accept the Ruby-natural one, store the MapLibre-native one — and the reasons matter.
Two conventions, both reasonable
When you write a coordinate in everyday speech, you almost always say latitude first, longitude second. Sydney is at latitude -33.87, longitude 151.21. Maps in atlases label latitudes on the side and longitudes on the top. Search engines expect “lat, lng” as the input format. GPS coordinates from a phone are formatted lat-then-lng. Most humans encounter coordinates as “latitude, longitude.”
But there’s another tradition. Mathematics and graphics
conventions put horizontal coordinate first, vertical
coordinate second — that’s (x, y) from primary school
geometry, mirrored in computer graphics where the X axis is
horizontal and the Y axis is vertical.
Mapped onto Earth, longitude is the horizontal coordinate (lines running north-south, varying east-west) and latitude is the vertical coordinate (lines running east-west, varying north-south). So the mathematical convention says longitude first, latitude second.
Both conventions are defensible. The first is more human-readable; the second is more mathematically consistent.
How different tools pick
A rough survey:
- Geography textbooks, search engines, address inputs: latitude first.
- GPS devices and phone location APIs: latitude first.
- PostGIS’s
ST_Point()function (and most spatial SQL): longitude first. - GeoJSON, the standard format for spatial data on the web:
longitude first. (The GeoJSON spec is explicit:
[longitude, latitude], and it cites the mathematical convention.) - Leaflet: latitude first. (
[lat, lng]— Leaflet picked the human-readable convention deliberately.) - MapLibre and Mapbox: longitude first. (
[lng, lat]— these libraries picked the GeoJSON-aligned convention because most data they consume is GeoJSON.)
So the libraries we’re using have landed on different conventions — Leaflet on lat-first, MapLibre on lng-first. This is one reason migrating from Leaflet to MapLibre is painful: every coordinate in your code has to be flipped.
Vera’s choice
The Vera gem accepts [lat, lng] in its DSL — the Ruby-natural
convention. Internally, it stores [lng, lat] because that’s
what MapLibre needs and what GeoJSON specifies.
Why the asymmetry?
- The DSL is what the developer writes. Reading and writing
[lat, lng]matches the way coordinates appear in databases, search results, GPS readouts, and conversation. Forcing[lng, lat]in the DSL would create a constant translation burden: copy-paste a coordinate from anywhere, mentally swap, type it. Errors compound. - The serialised configuration is what MapLibre consumes.
MapLibre expects
[lng, lat]and won’t accept anything else. GeoJSON, which the gem also produces and consumes, is similarly fixed at[lng, lat].
The gem hides the boundary. You write Ruby coordinates the
human way; they reach the browser the GeoJSON way. The
translation happens at the moment of serialisation, in
Vera::Coordinates.to_maplibre, and it’s the only place the
flip occurs.
You can verify this from Lesson 3’s Lab. Look at the data attribute on the rendered map div:
|
|
The centre is [133.77, -25.27] — longitude first, latitude
second. But the Ruby that produced it (in Vera::Map’s default
constants) is:
|
|
The gem’s constant is in [lat, lng] — the Ruby way. The
serialised JSON is in [lng, lat] — the MapLibre way. Same
information, two conventions, the gem bridges the gap.
The practical rule
When you write Ruby code for the gem, write [lat, lng].
Sydney: [-33.8688, 151.2093]. Brisbane: [-27.4698, 153.0251].
Eiffel Tower: [48.8584, 2.2945]. Always lat first, lng second.
When you’re inspecting JSON, looking at GeoJSON files, or working with raw MapLibre, the order flips: longitude first, latitude second. But in Ruby code targeting the gem, you don’t have to think about it.
That’s the rule. The rest of the lesson is about what to watch for at the boundary — when you bring coordinates in from elsewhere — and the consequences of getting it wrong.
When you copy coordinates from elsewhere
The danger zone is importing coordinates from external sources. Different sources use different conventions, and you have to know which is which before you paste them into Ruby code.
Sources that give you [lat, lng] (drop these directly into
the gem’s DSL):
- Google Maps URL parameters (the
q=lat,lngform) - Apple Maps share links
- Most “what are the coordinates of X?” search results
- Wikipedia’s geographic coordinates infobox
- GPS readouts from a phone or device
- The
latitudeandlongitudecolumns of most databases
Sources that give you [lng, lat] (you’ll need to swap):
- GeoJSON files of any kind
- The output of PostGIS’s
ST_AsGeoJSON()(or thecoordinatesarray from any GeoJSON feature) - MapLibre and Mapbox documentation
- Most JavaScript mapping examples
- The
geometrycolumn of a PostGIS table when extracted viaST_X()andST_Y()(X is longitude, Y is latitude)
If a source labels its values explicitly — “lat: -33.87, lng:
151.21” or {type: "Point", coordinates: [151.21, -33.87]} —
you can read off the convention. If a source just shows a pair
of numbers without labels, check the documentation. Or test
with a known-easy location: Sydney is around -33.87 N, 151.21
E. If a coordinate pair from your source produces [151, -33],
it’s [lng, lat]. If it produces [-33, 151], it’s [lat, lng].
What goes wrong when you swap them
When you accidentally pass [lng, lat] to the gem (because you
copied from GeoJSON without flipping), the gem dutifully
treats the numbers as [lat, lng]. Sydney’s
[151.21, -33.87] becomes a “coordinate” at latitude 151.21,
longitude -33.87.
MapLibre rejects latitude values outside the [-90, 90] range outright. The map fails to initialise and you’ll see a JavaScript error in the browser’s developer console, something like:
|
|
The error is precise about what went wrong (latitude out of
range), and the stack trace points at the vera--map
controller’s connect call as the place the error surfaced.
This is the classic symptom: an “Invalid LngLat” error in the console, the map div empty. When you see this, check coordinate order before checking anything else.
A more pernicious case is when both numbers happen to be
valid latitudes — for example, [40, 50]. Latitude 40,
longitude 50 is a real place (eastern Turkey); latitude 50,
longitude 40 is also real (western Russia). Reversing
coordinates that are both within [-90, 90] doesn’t error;
the map just shows the wrong location silently. This is rare
because longitudes in inhabited parts of the world are usually
beyond ±90, but it can bite for places near the prime meridian
or the equator.
Activity 1 — Get it wrong on purpose
Edit your Lab page’s render call and replace the centre with reversed Sydney coordinates:
|
|
(Notice this is [lng, lat] — the wrong order for the gem’s
DSL.)
Reload the page. The map area will be empty. Open the browser’s
developer console and you’ll see an error like
Invalid LngLat latitude value: must be between -90 and 90.
The number 151.2093 is being treated as a latitude, which
exceeds the valid range, and MapLibre refuses to initialise
the map at all.
Now fix the order:
|
|
Sydney appears as expected. Take a moment to internalise the difference: same numbers, different order, completely different result.
Worth remembering this error message specifically. When you see “Invalid LngLat” in your console weeks or months from now, the fix is almost always to swap the coordinate order somewhere upstream — in your view, in your seed data, in the GeoJSON your controller produces.
One more pattern
The gem also accepts [lat, lng] in markers, popup
positions, and the bounding-box action helpers. Anywhere a
coordinate is expressed in the gem’s DSL, it’s [lat, lng].
That’s a deliberate consistency.
You’ll see this throughout the rest of the tutorial. Markers,
flyto helpers, bounding-box queries, drawn shapes — all
coordinates pass through the same translation boundary, all
read as [lat, lng] in Ruby and [lng, lat] after
serialisation.
The one place this doesn’t hold is when you’re working
directly with GeoJSON your application produces or consumes.
GeoJSON is [lng, lat] by spec; if you’re hand-building a
GeoJSON object in Ruby for some reason, you write
[lng, lat] because that’s what GeoJSON requires. The Vera
gem doesn’t translate GeoJSON contents — they pass through
as-is.
In practice, hand-building GeoJSON in Ruby is rare. PostGIS
produces GeoJSON; Rails serialises it; the gem accepts URLs
that resolve to GeoJSON. The reader almost never writes
[lng, lat] in Ruby code by hand. But knowing it’s the
exception keeps you from being surprised when it comes up.
Activity 2 — Verify a coordinate’s order
Open https://www.google.com/maps in a browser. Right-click
anywhere on the map. The first item in the context menu shows
the coordinates of that point — for example, -27.4705, 153.0260
if you clicked on Brisbane.
Note the order: latitude first (negative for the southern
hemisphere), longitude second (positive for east of Greenwich).
That’s [lat, lng] — drop directly into the gem’s DSL.
Now find the same point on https://geojson.io. Click anywhere on the map. The right pane shows the GeoJSON representation:
|
|
The order is reversed: [lng, lat]. That’s GeoJSON’s
convention; you’d need to flip before pasting into the gem’s
DSL.
Same point, two formats, two orders.
Where this leaves us
You now know:
- Both
[lat, lng]and[lng, lat]are legitimate conventions, and different tools pick differently. - The gem accepts
[lat, lng]in its DSL — the Ruby-natural convention. - Internally, the gem flips to
[lng, lat]for MapLibre and GeoJSON consumption. - Most external sources give you
[lat, lng]directly (Google Maps, GPS, databases). GeoJSON gives you[lng, lat]and needs flipping. - An “Invalid LngLat” error in the console — or a map showing the wrong location — is almost always a reversed-coordinates bug.
Lesson 5 adds the controls that give the Lab map the polish of a real piece of UI — navigation, scale, attribution. After that, Module 2 is done and we move into PostGIS work proper in Module 3.