Cell & Shape

Guide

Lat/Lon vs Lon/Lat: which order does each format use?

Half of geospatial software wants longitude first; the other half wants latitude first. Nobody agrees, nothing errors when you get it wrong, and your points quietly end up in the ocean. This page is the definitive order table — one row per format and API, each sourced from its spec — plus how to recognise a swap on the map and fix it in one click, Python, JavaScript, or SQL.

Why two conventions exist

The disagreement is old and it is honest — both orders are "correct" for their world.

Mathematics uses (x, y). Longitude is the horizontal axis (east–west, the x) and latitude is the vertical axis (north–south, the y). Anything descended from computer graphics, computational geometry, or the OGC's Simple Features model inherits this: a coordinate is an (x, y) pair, so it is (longitude, latitude). GeoJSON, WKT, WKB, KML and Turf.js all live here.

Navigation uses (latitude, longitude). Sailors, pilots, and mapping APIs built for humans read a position out loud the way it appears on a chart — "forty-one point eight degrees north, eighty-seven point six west" — latitude first. Google Maps, Leaflet, the H3 and S2 libraries, and Google's encoded-polyline algorithm all speak this dialect.

Neither camp is wrong; they are answering different questions ("where is it on the plane?" versus "where is it on the globe?"). The problem is only that a bare pair of numbers carries no label, so the moment data crosses from one world to the other, the two values can silently trade places.

The definitive order table

Every row below is the order that format or library actually expects, per its own specification or API reference. When the "long" convention shows x y, remember x = longitude and y = latitude.

Format / API Order Detail & source
GeoJSON lon, lat RFC 7946 §3.1.1: a position is [longitude, latitude] in WGS84 decimal degrees. Longitude first, always.
WKT / WKB x y = lon, lat OGC Simple Features. A point is written POINT(x y) where x is easting/longitude and y is northing/latitude: POINT(-87.63 41.88).
PostGIS constructors lon, lat ST_MakePoint(x, y) and ST_Point(x, y) take (longitude, latitude). The classic trap is not the API — it is user code that writes ST_MakePoint(lat, lon) by habit. Order matters; the function won't warn you.
Google Maps JS API lat, lng new google.maps.LatLng(lat, lng) — latitude first, as the class name says. Same for { lat, lng } literals.
Leaflet lat, lng L.latLng(lat, lng), L.marker([lat, lng]), map.setView([lat, lng], z) — latitude first everywhere.
MapLibre / Mapbox GL JS lng, lat new LngLat(lng, lat); map.setCenter([lng, lat]). The GL stack is longitude-first — the opposite of Leaflet, a frequent migration bug.
Turf.js lon, lat It is GeoJSON under the hood: turf.point([lon, lat]), longitude first.
Encoded polyline lat, lng pairs Google's polyline algorithm encodes each vertex as (latitude, longitude) — latitude first. Feed it lon/lat pairs and the whole line transposes.
H3 (h3-js) lat, lng latLngToCell(lat, lng, res) (v4; geoToH3(lat, lng, res) in v3) — latitude first.
S2 lat, lng S2LatLng.FromDegrees(lat, lng) — latitude first, matching the class name.
EPSG:4326 axis order lat, lon (officially) The pedantic one. The EPSG registry defines the authoritative axis order of 4326 as latitude, longitude. Almost all software — GeoJSON, most WMS/tile clients, nearly every library above — ignores that and uses lon/lat anyway. The gap between "what the standard says" and "what everyone ships" is a long-running GIS in-joke; it mostly bites you in strict OGC WFS/GML services and some CRS-aware pipelines.
KML lon, lat <coordinates>lon,lat,alt</coordinates> — longitude first, comma-separated, optional altitude third.
CSV no standard The danger zone. There is no convention — columns may be lat,lng or lng,lat, sometimes headerless. Never assume; read the header, and if there isn't one, sanity-check a known point before trusting the whole file.

Rule of thumb: interchange & math formats are lon-first (GeoJSON, WKT, KML, Turf, MapLibre, PostGIS); human/navigation APIs are lat-first (Google Maps, Leaflet, H3, S2, polyline). The odd ones out — MapLibre being lon-first while Leaflet is lat-first — cause most real bugs.

What a swap looks like on the map

Swapping the two numbers reflects the point across the lon = lat diagonal. That single geometric fact explains every "my points are in the ocean" report.

Take Chicago: latitude 41.88, longitude -87.63. Correct GeoJSON is [-87.63, 41.88]. Write it the navigation way — [41.88, -87.63] — and a lon-first renderer reads longitude 41.88, latitude -87.63: a spot in the Southern Ocean off Antarctica, south of the Indian Ocean, roughly antipodal to where you meant. A northern-hemisphere city becomes a southern-ocean nowhere; that mirror-image relocation is the fingerprint of a swap.

The insidious part is the confusion band. When both numbers are ≤ 90 in magnitude, both orderings are geographically legal — every latitude is a valid longitude — so nothing throws, nothing warns, and the point just lands somewhere plausible-but-wrong. Chicago's swap falls squarely in this band: -87.63 is a perfectly valid latitude, so no validator on earth can be certain the pair is reversed. You only get a hard signal when a value exceeds ±90 — which can only be a longitude, proving the pair is out of order.

How our inspector's swap detector works (honestly)

The universal inspector runs a deliberately conservative swap heuristic. It flags a pair as possibly-swapped only when it can prove it: a coordinate whose latitude slot exceeds ±90° (geographically impossible) while its longitude slot would be a valid latitude (≤ 90°). That is the classic [lat, lon]-written-as-[lon, lat] mistake, and when it's found the validator raises a coordinates-possibly-swapped warning with a one-click swapCoords fix:

Coordinates look lon/lat-swapped: some latitudes exceed ±90° but would be valid longitudes. GeoJSON order is [longitude, latitude].

What it can catch: any swap where the mistaken latitude lands above 90 or below −90 — which covers every point whose true longitude is beyond ±90° (most of Asia, Oceania, the Pacific, the far Atlantic). What it cannot catch: the confusion-band swaps like Chicago, where the reversed latitude is still a legal number. There is no way to know for sure, so the inspector warns rather than silently swapping — silently "fixing" an ambiguous pair would be worse than leaving it, because it might have been right all along. It surfaces the ambiguity and lets you decide.

See it flag a swap

Here's a Tokyo point written the wrong way round as GeoJSON — [35.68, 139.65] instead of [139.65, 35.68]. Because Tokyo's longitude (139.65) is well past 90°, the swapped latitude slot is impossible, so the inspector catches it with certainty:

Open in the Inspector — watch it flag the swap →

The link carries the geometry in the URL fragment only, so nothing is uploaded — the inspector decodes it in your browser, parses it, and shows the possibly-swapped warning with the swapCoords fix button. You can also paste either snippet in yourself:

// Swapped (wrong) — inspector flags it, Tokyo latitude 139.65 is impossible
{"type":"Point","coordinates":[35.68, 139.65]}

// Correct — longitude first
{"type":"Point","coordinates":[139.65, 35.68]}

How to fix swapped coordinates

Once you know a dataset is reversed, flipping it is mechanical. Pick the tool you're already in:

In the inspector (one click)

When the validator raises coordinates-possibly-swapped, press its swapCoords fix. It transposes every position's first two values in place and re-validates, so you see the corrected geometry (and its map render) immediately.

Python (Shapely)

from shapely.ops import transform

# Swap x/y (lon/lat) for any geometry, holes and all.
flipped = transform(lambda x, y: (y, x), geom)

JavaScript (Turf / GeoJSON)

import { coordEach } from '@turf/meta';

// Mutates in place; works for points, lines, polygons, collections.
coordEach(geojson, (coord) => {
  const tmp = coord[0];
  coord[0] = coord[1];
  coord[1] = tmp;
});

PostGIS

-- Swap X and Y for a column of geometries.
UPDATE my_table SET geom = ST_FlipCoordinates(geom);

Flip once, then verify a known landmark before you trust the whole batch — a double-swap puts you right back where you started.

Sources and further reading

The table uses each format specification or library's current API reference. Where ecosystems disagree, the page reports the concrete function or serialized position order instead of assuming a universal convention.

Frequently asked questions

Is it latitude or longitude first?
It depends entirely on the format or library — there is no single answer, which is exactly why coordinates get swapped so often. The short version: data-interchange and math-derived formats put longitude first (GeoJSON, WKT/WKB, KML, Turf, PostGIS constructors, MapLibre and Mapbox GL), because they treat a position as (x, y). Human- and navigation-facing APIs put latitude first (Google Maps LatLng, Leaflet, the H3 and S2 libraries, and encoded polylines), because people say "lat, long". When in doubt, check the order table on this page or paste the coordinate into the inspector and let it flag an impossible latitude.
Why are my map points in the ocean?
Almost always because longitude and latitude are swapped. Swapping a pair reflects the point across the lon = lat diagonal, so a city in the northern hemisphere lands in the southern ocean and vice versa. Chicago at latitude 41.88, longitude -87.63 read in the wrong order becomes longitude 41.88, latitude -87.63 — a spot in the Southern Ocean off Antarctica, south of the Indian Ocean. If your points are consistently in the water at a mirror-image location, swap the two numbers.
Does GeoJSON use lat,lng?
No. GeoJSON uses [longitude, latitude] — longitude first. RFC 7946 §3.1.1 is explicit: a position is an array where the first two elements are longitude then latitude, in WGS84 decimal degrees. This trips up developers coming from Google Maps or Leaflet, where the order is reversed. WKT, KML, and Turf.js follow the same longitude-first order as GeoJSON.