CRS Governance and Reprojection Standards
Coordinate reference systems are the one dimension of a spatial product that cannot be renegotiated after the fact: get the CRS wrong and every distance, intersection, and join computed downstream is quietly incorrect while every schema field still validates. This reference sits inside Geospatial Data Mesh Fundamentals and defines how a federated estate governs CRS across many independently owned domains — declaring a canonical storage CRS, reprojecting only at domain boundaries, and delivering per output port in the projection each consumer expects. It builds directly on Spatial Domain Boundary Design, because the boundary is exactly where reprojection is allowed to happen, and on Metadata Cataloging for Raster/Vector, which records the declared crs_epsg that this governance enforces. The recurring failures it prevents are mundane and expensive: axis-order inversion, precision loss from repeated round-trips, and mercator-metre math applied to EPSG:4326 degrees.
Figure — Sources in mixed CRSs are reprojected to a canonical EPSG:4326 store at ingest, then reprojected again only at delivery into the projection each output port serves.
Architectural Boundaries & Design Rationale
CRS governance rests on one principle: there is exactly one canonical storage CRS for the mesh, and every product is reprojected into it at the moment it crosses an ingest boundary. This site standardizes on EPSG:4326 for canonical storage — the concrete rollout is documented in Standardizing on EPSG:4326 Across Domains — while delivery ports may serve any approved projection the consumer needs. Reprojection is confined to the two boundaries, ingest and delivery, and is forbidden in the interior. That confinement is not stylistic; it directly eliminates the failure modes that a federated estate accumulates when every domain reprojects wherever it likes.
Four concrete failures motivate the standard:
- Axis-order inversion.
EPSG:4326is officially latitude-then-longitude, but most tooling and every GeoJSON payload use longitude-then-latitude. A domain that follows the authority order where its neighbours follow the tooling order produces geometry that lands in the wrong hemisphere. The contract must assertlon_latexplicitly, exactly as Data Contracts for Spatial Products records it. - Repeated round-trip precision loss. Reprojecting
4326 → 3857 → 4326across successive interior hops accumulates floating-point drift and can shift vertices by centimetres to metres. Reprojecting only at boundaries caps the number of transforms a coordinate ever undergoes. - Mercator-metre math on degrees. A consumer that runs a buffer or distance query assuming metres against
EPSG:4326degrees computes a nonsense result that no schema check catches. - Silent cross-domain CRS mismatch. Two domains joined on a shared extent but stored in different CRSs produce empty or shifted joins. A single canonical store makes every interior geometry comparable by construction.
The delivery side is where governance meets consumer reality. A tile port serves EPSG:3857 because web map clients demand web mercator; a features port serves EPSG:4326 for OGC API Features. Both reproject from the canonical store at the output boundary, so the store never holds more than one projection and the ports never leak a non-canonical CRS back into storage.
Specification & Contract Reference
CRS governance is expressed as a small set of enforceable parameters attached to every domain and output port. These are validated at registration and at the boundary gate.
| Parameter | Scope | Constraint / Convention | Rationale |
|---|---|---|---|
canonical_crs |
Mesh | EPSG:4326 |
Single interior projection; never overridden per domain |
canonical_axis_order |
Mesh | lon_lat |
Explicit to defeat authority/tooling ambiguity |
source_crs_allowlist |
Ingest | [4326, 3857, 4269, 32610, 32611, 32633] |
Only approved projections may be reprojected in |
reproject_boundaries |
Topology | ingest, delivery |
Interior reprojection is prohibited |
delivery_crs |
Output port | 3857 (tiles) | 4326 (features) |
Per-port projection served to consumers |
min_precision_decimals |
Quality | 6 (~0.11 m) |
Guards against round-trip precision loss |
transform_pipeline |
Governance | Named PROJ pipeline or EPSG code | Pinned so a transform is reproducible and auditable |
datum_shift_grid |
Governance | e.g. null | NAD83→WGS84 |
Declared when a datum shift is required, not implicit |
The distinction between a bare CRS change and a datum shift matters: reprojecting EPSG:32633 to EPSG:4326 is a coordinate operation within the WGS 84 datum, whereas moving from EPSG:4269 (NAD83) involves a datum transformation whose grid must be declared and pinned. Leaving the datum shift implicit is how “correct” reprojections drift by a metre.
Production Implementation
Reprojection at a boundary must be idempotent and reproducible: the same input and the same pinned transform always yield byte-comparable geometry, and re-running the step never compounds error. Below, ogr2ogr normalizes an incoming vector source to the canonical EPSG:4326 at the ingest boundary, and a PostGIS ST_Transform produces the EPSG:3857 delivery view — followed by a validation query that proves the transform did not silently corrupt the extent. Zero-trust applies here too: the boundary trusts only the declared source CRS after verifying it against the allowlist, never a guessed projection.
#!/usr/bin/env bash
set -euo pipefail
SRC="${1:?source dataset}" # e.g. parcels_utm33.gpkg (EPSG:32633)
SRC_EPSG="${2:?declared source EPSG}"
# Zero-trust: refuse any source CRS outside the enterprise allowlist.
case "$SRC_EPSG" in
4326|3857|4269|32610|32611|32633) ;;
*) echo "FATAL: EPSG:${SRC_EPSG} not in source allowlist"; exit 1 ;;
esac
# Reproject to canonical EPSG:4326 at the ingest boundary.
# -s_srs is set explicitly (never trust the file's embedded CRS blindly);
# lon/lat axis order is forced so authority ordering cannot leak in.
ogr2ogr -f GPKG parcels_4326.gpkg "$SRC" \
-s_srs "EPSG:${SRC_EPSG}" -t_srs EPSG:4326 \
-lco GEOMETRY_NAME=geom --config OGR_CT_FORCE_TRADITIONAL_GIS_ORDER YES
echo "normalized ${SRC} (EPSG:${SRC_EPSG}) -> EPSG:4326"
-- Canonical storage holds EPSG:4326; delivery views reproject at the output port.
-- ST_Transform is deterministic for a pinned source/target pair.
CREATE MATERIALIZED VIEW parcels_tiles_3857 AS
SELECT parcel_id,
ST_Transform(geom, 3857) AS geom -- delivery boundary → web mercator
FROM parcels_4326; -- interior stays EPSG:4326
-- Validation: the reprojected extent must round-trip back within tolerance,
-- proving no axis flip or datum drift crept in at the boundary.
SELECT parcel_id
FROM parcels_tiles_3857 t
JOIN parcels_4326 c USING (parcel_id)
WHERE NOT ST_Equals(
ST_SnapToGrid(ST_Transform(t.geom, 4326), 0.000001),
ST_SnapToGrid(c.geom, 0.000001)
);
-- Zero rows returned == reprojection is lossless within 1e-6 degrees.
Run the validation query in CI after every reprojection change. A non-empty result set means the transform pipeline, the source CRS declaration, or the axis order is wrong — and the delivery view must be rebuilt before it is published, never patched in place.
Diagnostic Runbook
When consumers report geometry in the wrong place, empty joins, or distances that make no sense, isolate the CRS fault in order.
- Confirm the declared source CRS. Run
ogrinfo -so -al source.gpkg | grep -i srsand compare againstsource_crs_allowlist. A source outside the allowlist should have been rejected at ingest. Remediation: reproject upstream to an allowlisted CRS or add the projection through a governed allowlist change, never silently. - Check axis order. If features are mirrored or in the wrong hemisphere, the boundary likely honored authority lat/lon order. Remediation: force
OGR_CT_FORCE_TRADITIONAL_GIS_ORDER YES(or PostGISST_FlipCoordinateson the offending set) and re-run. - Detect interior reprojection. Search pipeline code for
ST_Transform/-t_srscalls outside the ingest and delivery boundaries. Remediation: remove them; the interior must remainEPSG:4326. - Measure round-trip drift. Run the validation query from the implementation section. Remediation: if rows return, pin the
transform_pipelineand, for datum-shifted sources, install and declare thedatum_shift_grid. - Verify delivery projection. Confirm the tile port serves
EPSG:3857and the features port servesEPSG:4326withST_SRID(geom). Remediation: rebuild the materialized view with the correct target SRID. - Reconcile against the catalog contract. Cross-check the served CRS against the declared
crs_epsgrecorded in Metadata Cataloging for Raster/Vector. Remediation: if they diverge, the contract or the port is wrong; treat any change tocrs_epsgas a breaking version bump.
SLA Targets & Performance Baselines
CRS governance carries measurable guarantees that feed the mesh’s alerting.
| Metric | Target | Alert Threshold | Remediation Action |
|---|---|---|---|
| Round-trip reprojection error | < 1e-6 degrees | any row failing the validation query | Pin transform pipeline; install datum grid |
| Non-canonical interior geometry | 0 features | any interior SRID ≠ 4326 | Remove interior transform; re-normalize at ingest |
| Axis-order inversions | 0 | any mirrored feature detected | Force lon/lat order; flip and re-publish |
| Source CRS allowlist violations | 0 admitted | any out-of-allowlist source registered | Reproject upstream; deny at ingest gate |
| Delivery reprojection latency (p95) | < 200 ms | > 500 ms for 5 min | Materialize view; add spatial index on delivery |
| Datum-shift declaration coverage | 100% of shifted sources | any implicit datum change | Declare and pin datum_shift_grid |
Datum Shifts and the Metre Nobody Sees
The failure that CRS governance exists to prevent is almost never a visible one. A dataset reprojected through the wrong datum transformation does not look wrong: the polygons are valid, the topology is intact, the extent is plausible, and the features land within a few metres of where they belong. Nothing in a rendering pipeline, a topology check, or a schema validator will object. The error surfaces months later, when a utility crew digs where a reprojected asset said the cable was and finds it two metres away.
The mechanism is worth stating precisely because it is routinely conflated with projection. A projection change is mathematical and lossless within its own datum: converting EPSG:4326 to EPSG:3857 is a closed-form transformation of the same underlying positions onto a different plane. A datum change is empirical: it relates two different models of the Earth’s shape and orientation, and the relationship between them is measured, not derived. Going from a national datum to WGS 84 is not a formula; it is a best-fit approximation, and the quality of that approximation depends entirely on which transformation you used.
| Transformation method | Typical accuracy | When it is correct to use |
|---|---|---|
| Null / identity (assumed same datum) | 0 m, or 100+ m if wrong | Only when both CRS genuinely share a datum |
| 3-parameter Helmert (geocentric translation) | 3–10 m | Coarse regional work where no grid exists |
| 7-parameter Helmert (position vector / coordinate frame) | 1–3 m | Continental-scale work with published parameters |
Grid-based (NTv2, GEOID, .gsb shift files) |
0.01–0.2 m | Survey-grade work; the only acceptable method for cadastral data |
The governance requirement follows directly: the transformation is part of the contract, not an implementation detail of whoever ran the reprojection. A product that declares EPSG:4326 has said what its coordinates mean only if it also records how it got there from the source datum. Two artifacts of the same parcel, both correctly labelled EPSG:4326, can differ by metres if one went through a 3-parameter Helmert and the other through an NTv2 grid — and a consumer joining them will produce slivers, gaps, and false topology errors that look like data-quality problems in the source.
In practice this means three things a domain must do. Pin the transformation pipeline explicitly rather than letting the library choose: modern PROJ selects a “best available” transformation based on the grids installed on the machine, so the same command on two workers with different grid packages produces different coordinates. Record the pipeline and the PROJ version in the artifact’s metadata, so an unexplained shift can be diagnosed rather than argued about. And ship the grid files as a versioned dependency of the pipeline image, not as an operator’s local installation — a reprojection whose result depends on what happened to be installed on the machine that ran it is not reproducible, whatever the cache key says.
The one case that deserves a hard stop is a source with no declared datum at all. There is a persistent temptation to assume WGS 84, because most modern data is, and because the assumption is right often enough to feel safe. It is the single most expensive assumption in the field: when it is wrong, the error is a systematic offset across the entire dataset, it is invisible to every automated check, and it propagates into every derived product before anyone notices. Fail the ingest, quarantine the artifact, and make the producing domain declare it.
A last governance point concerns vertical position, which is routinely forgotten because most spatial products are treated as two-dimensional. Elevation is measured against a vertical datum — an ellipsoid, a geoid model, or a local tidal datum — and these differ from each other by tens of metres in places. A product carrying z values without declaring its vertical datum has published numbers whose meaning is unknown, and the failure is worse than the horizontal case because there is no visual check at all: a building height, a flood level, and a bathymetric depth all look reasonable regardless of which surface they were measured from. Where a product publishes elevation, the vertical datum belongs in the contract alongside the horizontal CRS, and a transformation between vertical datums requires a geoid model shipped and versioned exactly like a horizontal grid.
Finally, the governance body’s job here is narrow and worth keeping narrow. It sets the canonical storage CRS, maintains the approved transformation registry, and owns the grid package that pipelines depend on. It does not review individual reprojections, and it does not arbitrate which CRS a domain works in internally. A CRS council that reviews changes case by case becomes the bottleneck the mesh was built to remove; one that publishes an approved transformation registry and lets automated checks enforce it scales without becoming a queue.
Audit expectations follow from all of this. Because a reprojection’s result depends on the transformation, the grid package, and the library version, an audit of a positional claim needs all three recorded against the artifact — not merely the source and target CRS. The minimum record that makes a coordinate defensible is the source CRS as declared by the producer, the target CRS, the transformation pipeline actually applied, the grid package version, the PROJ version, and the identity of the run that produced it. Every one of those is available at pipeline runtime and costs nothing to persist; reconstructing any of them afterwards ranges from tedious to impossible. Where positional accuracy carries legal or safety weight — cadastral boundaries, utility networks, flood extents used in planning decisions — that record is the difference between a defensible answer and an argument.
Governance & Compliance Notes
CRS is a compliance surface, not merely a technical one. Only projections on the source_crs_allowlist may enter the mesh, because an unapproved projection silently breaks every cross-domain join and undermines downstream SLAs, and the allowlist is the single enforcement point for that rule. Every reprojection at a boundary emits an audit event recording the source CRS, target CRS, the pinned transform_pipeline, and any datum_shift_grid applied — this trail is what lets an auditor reconstruct exactly how a coordinate reached its delivered position. Because a CRS change is never backward-compatible, it is always governed as a breaking change under Versioning Spatial Data Contracts with SemVer: the crs_epsg in the contract and the projection served at the port must agree, and any divergence forces a major version and a parallel migration rather than an in-place edit. Held to this standard, the mesh keeps one canonical truth, reprojects only where it is accountable to, and delivers each consumer the projection it needs without ever polluting the interior.
Related
- Geospatial Data Mesh Fundamentals — parent reference and architectural overview
- Standardizing on EPSG:4326 Across Domains — the concrete rollout of the canonical storage CRS
- Spatial Domain Boundary Design — the boundaries where reprojection is permitted
- Metadata Cataloging for Raster/Vector — records the declared CRS this governance enforces
- Data Contracts for Spatial Products — the contract surface that pins CRS and axis order