Short answer

When layers do not line up, the cause is almost always a coordinate reference system (CRS) problem, and there are only a few flavours: a missing CRS (no .prj/no declared SRID), a wrong declared CRS (the metadata says one thing, the coordinates are another), a datum difference (same projection, different geodetic datum, so a tens-of-metres offset), or an axis-order issue (lat/long swapped). Each has a different fix, so the first job is to classify the failure, not to start nudging layers.

The trap is that on-the-fly reprojection in QGIS or ArcGIS can make layers display together even when one is mislabelled, hiding the error until you measure, clip, or run terrain analysis and get wrong numbers.

Diagnose by reading coordinates, not the map

Turn off the basemap and look at raw extents. In QGIS, layer Properties → Information shows the extent in the layer's own CRS. Tell-tale signs:

  • Coordinates around (7.1, 43.6) are geographic (degrees, WGS84 / EPSG:4326).
  • Coordinates around (320000, 4760000) are projected (metres, e.g. UTM).
  • Coordinates around (792000, 1843000) might be a national grid (Lambert, State Plane, British National Grid).

If one layer reports degrees and another metres, both can still be correct provided each one's declared CRS matches its numbers. The misalignment appears when a layer's numbers belong to one CRS but its metadata claims another.

A fast triage:

ogrinfo -so -al layer.shp | grep -A3 -i "PROJCRS\|GEOGCRS\|Extent"
gdalsrsinfo layer.shp        # what CRS is declared

For a shapefile, check that .prj exists at all; if it is missing, the layer has no CRS and the software is guessing.

Case 1 — Missing CRS (no .prj)

A shapefile without a .prj has no declared CRS. The software falls back to the project CRS or "unknown", so the raw coordinates get interpreted in the wrong system and the layer jumps. The fix is to assign the layer's true source CRS, which you determine from the data provider, the coordinate magnitude, or a known landmark, not by experiment.

In QGIS use Vector → Data Management → Assign Projection (or set the layer CRS and re-export). With GDAL:

ogr2ogr -a_srs EPSG:27700 fixed.shp broken.shp   # -a_srs assigns, no coordinate change

-a_srs only writes the label; it does not move coordinates. That is exactly what you want when the geometry is already correct.

Case 2 — Wrong declared CRS

Here the .prj exists but is wrong (a common result of someone assigning a CRS to "fix" a display problem). The symptom is a layer that is internally consistent but offset or warped relative to everything else. The fix is the same -a_srs / Assign Projection, but to the correct source CRS. If you have already exported with the wrong label baked in, you may need to assign the correct label and then verify against a control point.

The rule that prevents most of this mess: assign vs reproject.

  • Assign (-a_srs, Assign Projection): coordinates already correct, metadata missing/wrong → relabel only.
  • Reproject (-t_srs, Reproject Layer, ST_Transform): metadata correct, you need different coordinates → transform.

Using assign when you should reproject is the single most destructive mistake, because it tells the software the metres are degrees (or vice versa) and the data lands on the wrong continent.

Case 3 — Datum shift

Two CRSs can use the same projection but different datums, so identical ground points have slightly different coordinates. Classic pairs: NAD27 vs NAD83 (up to ~100 m in parts of North America), ED50 vs ETRS89/WGS84 in Europe (often 50–200 m), or older national datums vs their modern replacements. Layers display "almost" aligned, offset by a consistent vector.

The fix is a proper datum transformation, which PROJ handles. Reproject with the right transformation pipeline rather than a same-projection relabel:

gdalwarp -s_srs EPSG:4267 -t_srs EPSG:4326 in.tif out.tif   # NAD27 -> WGS84
ogr2ogr -t_srs EPSG:4258 -s_srs EPSG:4230 out.shp in.shp     # ED50 -> ETRS89

When high accuracy matters, prefer the official grid-shift transformation (e.g. NTv2 grids) over a 3-parameter Helmert; PROJ will use the grid if it is installed. In QGIS, the Transformation dialog lets you pick the specific operation and reports its expected accuracy.

Case 4 — Axis order

Some authorities define EPSG:4326 as latitude-then-longitude. A few tools read it longitude-first. The symptom is data flipped across the diagonal or sitting in the wrong hemisphere. The fix is to force the axis interpretation, e.g. GDAL's OAMS_TRADITIONAL_GIS_ORDER behaviour, or set -t_srs "EPSG:4326" consistently and check whether your tool honours the authority's axis order. This bites most often with WFS/GML and some WKT round-trips.

Worked diagnostic walk-through

A project has: a boundary in British National Grid (EPSG:27700, coords ~530000, 180000), a public geology layer in WGS84 (coords ~-0.1, 51.5), a survey shapefile with no .prj, and an OSM basemap in Web Mercator (EPSG:3857). On screen they roughly overlap thanks to on-the-fly reprojection, but a distance measurement is wrong.

  1. The boundary and geology are fine: declared CRS matches their numbers.
  2. The survey shapefile has no .prj. Its coordinates are ~530000, 180000, so it is BNG; assign EPSG:27700 (-a_srs EPSG:27700).
  3. For any measurement, area, buffer, or DEM clip, reproject the working layers into the projected CRS of the area (EPSG:27700 here), never the WGS84 or 3857 view.
  4. Record the chain: source CRS → processing CRS (27700) → output CRS.

Why Web Mercator is not for measurement

EPSG:3857 (Web Mercator) is a display CRS. Its scale factor grows with latitude, so distances and areas are distorted, badly at high latitudes. On-the-fly reprojection into 3857 makes layers look aligned but a buffer or area computed there is wrong. Reproject into an equal-area or local UTM/national projection for any calculation, then return to 3857 only for the web display.

Common pitfalls and why they happen

  • Measuring in Web Mercator because it is the default basemap CRS, so it feels canonical. It is not metric truth.
  • Assigning a CRS to force a layer to move, which corrupts the metadata permanently.
  • Buffering or computing area on degrees, which produces "square-degree" nonsense.
  • Ignoring vertical units/datum when elevation is involved (feet vs metres, orthometric vs ellipsoidal heights) — the horizontal can line up while the heights are off.
  • Skipping the datum transformation because the layers look close enough.

QA and validation

Before exporting any map or analysis: confirm every layer's declared CRS matches its coordinate magnitudes; verify alignment against a trusted reference (a known road junction, a survey monument) rather than eyeballing the basemap; measure a known distance to confirm the working CRS is metric and correct; and write down the source, processing, and output CRS plus the transformation used. For datum-sensitive work, note the transformation's stated accuracy.

Bathyl perspective

We treat the CRS chain as a deliverable in its own right: source CRS, the assign-or-reproject decision, the datum transformation, and the output CRS, all documented so another analyst can audit the geometry. A map that aligns on screen but has no recorded coordinate logic is not finished work.

Related reading

Sources