OSM Feature Identity & ID Stability Jump to heading

An OpenStreetMap identifier is a name for a database object, not for a thing in the world. Most pipelines assume otherwise, and the assumption holds until somebody splits a road.

Four ordinary edits and what each one does to a stored identifier Four panels. A retag leaves the identifier unchanged and increments the version, so a stored reference still resolves and the feature is still the same thing. A split keeps the original identifier on one part and creates new ones for the others, so a stored reference resolves to a fragment of what it named. A merge deletes one identifier and keeps another, so half of any stored references stop resolving. A replacement, such as a way becoming a multipolygon relation, retires the identifier entirely and a stored reference resolves to nothing. Four edits, four different fates for a stored reference Retag Id unchanged Version increments Reference still resolves Still the same thing Split One part keeps the id Others get new ones Resolves to a fragment Silently wrong Merge One id is deleted The other survives Half the references break Loudly, at least Replacement Way becomes a relation Old id retired Resolves to nothing Or worse, to reuse Only the first panel leaves a stored reference meaning what it meant, and the second is the dangerous one because nothing errors.
A split is the common case and the silent one: the identifier still resolves, to a shorter road than the one you stored.

The Problem This Topic Solves Jump to heading

Your pipeline stores references to OSM features — a conflation match, a cached geocode, a curated list of interesting objects, an enrichment join key — and needs them to still be right next month. Whether they are depends entirely on what an identifier guarantees, which is less than most people assume.

The failure scenario is quiet. A team stores way identifiers for a curated set of cycle routes. Six months later a mapper splits several of those ways at junctions, which is routine and correct mapping. Every stored identifier still resolves, so nothing errors — but each now names a fragment of the route it used to name, and the pipeline’s length statistics quietly drop by forty percent. Nobody notices until somebody compares against an external figure.

What an Identifier Actually Guarantees Jump to heading

Four properties, and it is worth being precise about each.

Identifiers are scoped by type. A node, a way and a relation can all carry the identifier 12345, and they are three unrelated objects. The unique key is the pair, which is why every table in this section carries a composite key rather than a bare number.

Identifiers are not reused after deletion. A deleted object’s identifier is retired, so a stored reference to a deleted feature resolves to nothing rather than to something else. That is a genuinely useful guarantee and it is why deletion is the least dangerous of the four edits above.

Versions increment on every edit. The version number tells you the object changed; it does not tell you how or whether the change matters to you. A version bump from a typo fix and one from a complete retagging look identical.

Nothing guarantees the object still means the same thing. An identifier names a database row. What that row represents can change entirely — a building becoming a shop, a road being re-purposed, a boundary being redrawn — with no signal beyond a version increment.

The Four Edits That Break Assumptions Jump to heading

Retagging is benign for identity: the identifier and the geometry are unchanged, and only the meaning may have moved. A stored reference still names the same object.

Splitting is the dangerous one. When a way is split, one part conventionally keeps the original identifier and the others are new objects. A stored reference still resolves, silently, to a shorter feature. Nothing errors; statistics simply change.

Merging deletes one identifier and keeps another. Stored references to the deleted one stop resolving, which at least fails loudly.

Replacement happens when a feature’s representation changes form — a closed way becoming a multipolygon relation is the common case. The old identifier is deleted and a new object of a different type appears. A stored reference resolves to nothing, and a pipeline that only looked at ways never sees the replacement.

How each edit affects the three things a pipeline might rely on A grid of four edit kinds against whether the identifier still resolves, whether the geometry still describes the same extent, and whether a stored reference is still correct. Retagging leaves all three intact except that the meaning may have changed. Splitting leaves the identifier resolving but the geometry covering less, so the reference is wrong without erroring. Merging breaks resolution for one of the two identifiers, which fails loudly. Replacement breaks resolution entirely and changes the object type as well. Three things to rely on, and how each edit treats them Resolves? Same extent? Still correct? Retag yes yes meaning may differ Split yes no, shorter no, and silent Merge one of two no, longer no, but loud Replacement no n/a no, and loud The split row is the only one where every check a naive pipeline performs passes while the answer is wrong.
Designing for the split case covers the others; designing for deletion alone covers almost nothing.

Where Identity Assumptions Hide Jump to heading

Identity assumptions rarely announce themselves. They sit inside code that reads perfectly well and only becomes wrong when the map moves. Four places are worth auditing in any existing pipeline.

Join keys. Any join on a bare numeric identifier is assuming uniqueness that does not hold across element types. The symptom is a result set larger than expected, which looks like a legitimate many-to-many relationship rather than like a bug.

Cached geometry. A stored polygon or line keyed on an identifier is assuming the geometry has not changed. That assumption is usually fine for a building and routinely wrong for a road, and nothing in the cache indicates which kind it holds.

Curated lists. A hand-assembled set of interesting features — the routes a product covers, the sites a report describes — is the highest-value and most fragile identity assumption in most pipelines, because it was built by a human who will not be watching it.

Aggregate comparisons across time. Any figure compared against the same figure last quarter assumes the underlying features are the same features. A split changes the count without changing anything on the ground, and a comparison that does not account for that reports a change that did not happen.

The common thread is that none of these produce an error. Each produces a plausible number, which is why the audit has to be deliberate rather than driven by incidents — by the time an incident occurs, the wrong numbers have usually been reported for months.

Building Something That Survives Jump to heading

Three techniques, in increasing order of effort and robustness.

Store the version alongside the identifier. A stored reference becomes a pair, and re-resolving compares the current version against the stored one. That does not tell you what changed, but it tells you that something did, which turns a silent drift into a review item. It is the cheapest possible improvement and it catches the split case, because the surviving part’s version increments.

Store enough to re-verify. A coordinate, a name, a length — whatever the reference was for. Re-resolving then checks not just that the object exists but that it still looks like what you stored. A route whose length halved is a re-verification failure even though the identifier resolved.

Prefer an external identifier where one exists. A ref:* tag, an operator’s code or a knowledge-base link survives splits and replacements, because it describes the thing rather than the database row. Linking OSM Features to Wikidata Identifiers covers establishing those deliberately, and they are the only references in this section that are genuinely durable.

For internal purposes, a surrogate key — a stable identifier your pipeline mints and maps to OSM objects — decouples your data model from the map’s churn entirely. Building Stable Surrogate Keys for OSM Features develops it.

Four levels of reference durability, from fragile to genuinely stable Four approaches in increasing order of robustness. Storing a bare numeric identifier is the most fragile, colliding across element types and silently resolving to a fragment after a split. Adding the element type removes the collision but leaves everything else. Adding the version turns silent drift into a detectable change, because any edit increments it. Adding a verifiable attribute such as length or a coordinate catches the split case specifically. An external identifier is the only form that survives splits and representation changes without any re-resolution at all. Each level catches one more failure bare id collides across types most fragile type plus id collision fixed split still silent plus version change detectable not what changed plus attribute split detectable re-verify on resolve An external identifier sits beyond the fourth step: it names the thing rather than the row and needs no re-resolution at all.
Most pipelines stop at the second step, which fixes the loud failure and leaves the silent one entirely intact.

What to Store, Concretely Jump to heading

A stored reference that survives ordinary editing carries five fields, and each earns its place.

The element type and identifier together form the key. The version at capture time makes any later change detectable. A verifiable attribute — whichever property the reference exists to describe — makes a split or a retagging detectable rather than merely a change. And the capture date explains drift when somebody asks why a figure moved, because it establishes what the map looked like when the reference was made.

That is five small columns. The temptation to store only the identifier is strong precisely because it works: everything resolves, nothing errors, and the cost appears months later as a number nobody can explain.

Validation and Error Handling Jump to heading

Condition Root cause Detection Remediation
Statistics drop with no code change Ways split upstream Aggregate measures fall; ids still resolve Store versions and re-verify attributes
Joins produce duplicates Joined on a bare numeric identifier Same number across element types Key on the type and identifier pair
Reference resolves to nothing Object deleted or replaced Not-found on re-resolution Expected; route to review rather than dropping
A way became a relation Representation changed form Identifier gone, similar feature nearby Search by attributes, not only by identifier
Stale meaning, current identifier Retagged into something else Attributes no longer match what was stored Re-verify stored attributes, not just existence
Nothing ever re-checked References stored and never revisited Quality decays invisibly Re-resolve on a schedule tied to edit rates
History unavailable for a fix Only current state retained Cannot see what the object used to be Consult a history file for the prior state

Re-Resolution as a Scheduled Job Jump to heading

References decay, and the only reliable response is to re-resolve them on a schedule. Two design points make that affordable.

Batch by area, not by record. Re-resolving a thousand scattered identifiers is a thousand requests; re-resolving everything in one region is one extract read. For any volume, the file-based route from Choosing Between Overpass and a Local Extract is the right one.

Drive the schedule from edit rates. An area with heavy mapping activity needs re-resolution far more often than a stable one, and the replication stream already tells you which is which. Using the diff stream to mark regions as dirty — the pattern in Incremental Updates for Derived Datasets — turns a blanket weekly sweep into targeted work.

Guides in This Topic Jump to heading

Frequently Asked Questions Jump to heading

Are OSM identifiers unique on their own?

No. They are scoped by element type, so a node, a way and a relation can each carry the same number while being entirely unrelated objects. The unique key is the pair of type and identifier, and joining on the bare number produces phantom duplicates that are easy to miss because they look like genuine multiple matches rather than like an error.

Are identifiers reused after an object is deleted?

No, and this is one of the few genuinely strong guarantees available. A deleted object’s identifier is retired, so a stored reference to it resolves to nothing rather than to some unrelated feature that inherited the number. That makes deletion the least dangerous of the ways a stored reference can go wrong, because it fails loudly and unambiguously.

What happens to my stored reference when a way is split?

It keeps resolving, to a shorter way. Conventionally one part retains the original identifier and the other parts become new objects, so nothing errors and nothing indicates that the feature you stored is now a fragment. This is the most damaging identity failure precisely because every check a naive pipeline performs passes. Storing the version and an attribute such as length, and re-verifying both, is what catches it.

Does a version increment tell me what changed?

Only that something did. A version bump from a corrected spelling and one from a complete retagging are indistinguishable from the number alone. Comparing versions is still worthwhile because it converts silent drift into a review item, but deciding whether the change matters requires either comparing the stored attributes against the current ones or fetching the previous version and diffing them.

Is there any genuinely durable reference to an OSM feature?

An external identifier, where one exists — a published reference code, an operator’s own identifier, a knowledge-base link. Those describe the thing in the world rather than the database row, so they survive splits, merges and representation changes that retire an OSM identifier. Establishing such links deliberately is more work up front and is the only approach that does not require periodic re-resolution.

Up one level: OSM Data Fundamentals & Architecture.