Written for the integration architect and standards-minded engineer, with accuracy as the deliberate differentiator: the value-set-to-value-set scoping of concept maps and the correct reading of code system properties are the details generic explainers get wrong, and getting them right is what earns this audience's trust. Applicable on both sides of the Atlantic (SNOMED CT, LOINC and ICD-10 travel well), with NHS texture kept light. Anchors the SNOMED governance, ICS terminology mapping and UK Core pieces that follow.
A familiar project stall: two systems both "use SNOMED CT", the integration between them is live, and yet the receiving system keeps rejecting perfectly valid codes. The workshop that follows runs long, because everyone in the room is using the words "code system", "value set" and "codes" interchangeably, and they are not the same thing.
Almost every terminology argument in healthcare integration reduces to those three concepts being blurred. Separate them cleanly and most of the arguments dissolve.
In brief
A code system is a dictionary: a maintained catalogue of concepts with identifiers, like SNOMED CT, LOINC or ICD-10. A value set is a shortlist: a curated selection of codes, drawn from one or more code systems, fit for one specific context like a form field or a message element. A concept map is a translation: a maintained set of correspondences between the codes in one value set and the codes in another. Systems don't exchange "SNOMED"; they exchange codes from agreed value sets, and when their value sets differ, a concept map bridges them.
Why the vocabulary matters
Terminology work is where clinical safety and integration engineering meet. A dropdown bound to the wrong list, a code translated to a broader concept than intended, a locally invented code leaking into a shared record: each of these is a data quality problem on the way to becoming a clinical one. The engineering is rarely the hard part. The hard part is that teams commission "SNOMED integration" without agreeing which of the three layers they're actually talking about, and the FHIR specification is precise about these layers in ways most explainers gloss over. This one won't.
Code systems: the dictionaries
A code system is an authoritative catalogue of concepts, each with a unique identifier, a human-readable display, and usually a web of relationships and properties. SNOMED CT for clinical concepts. LOINC for observations and lab tests. ICD-10 for classification. In the UK, dm+d for medicines and devices. Each is maintained by a publisher, versioned on a release cycle, and enormous: far too large to ever present to a user whole.
Two properties of code systems matter for integration work. First, concepts carry structure: SNOMED CT concepts sit in hierarchies and have defining relationships, which is what makes rule-based selections possible later. Second, and this trips people up in FHIR terms, a code system's properties describe its concepts; they don't tell you which concepts are appropriate for your screen, your message, or your use case. The dictionary defines the words. It doesn't write your sentence.
Value sets: the shortlists
A value set answers the question the code system can't: which codes are valid *here*? It's a curated selection, assembled for one purpose: the allergy field on an admission form, the specimen type element in a lab message, the ethnicity codes a national dataset accepts.
Two things make value sets more interesting than a simple list. First, a value set can draw from more than one code system; a single shortlist might legitimately mix SNOMED CT concepts with codes from a national administrative system. Second, there are two ways to define one. An extensional definition enumerates the exact codes. An intensional definition states a rule instead: "every descendant of this SNOMED CT concept", for example. Intensional definitions stay current as the underlying code system evolves, which is usually what you want, and the $expand operation is what turns the rule into the concrete list of codes at the moment you need it.
When someone says "the system validates against SNOMED", what a well-built system actually does is validate against a named, versioned value set. That distinction is the difference between governance and hope.
Concept maps: the translations
Systems disagree. Your Trust's legacy codes, a supplier's proprietary list, SNOMED CT on one side and ICD-10 on the other: sooner or later, data crossing a boundary needs translating, and a concept map is the maintained artefact that does it. Each entry pairs a source code with a target code and states the relationship: equivalent, broader, narrower.
Here's the detail that separates FHIR-correct understanding from the folk version: a concept map's source and target are value sets, not entire code systems. You are never really mapping "SNOMED to ICD-10"; you are mapping the codes we use in this context to the codes they accept in that context. That scoping is what makes a map finite, testable and ownable. A map between two whole code systems is a research programme. A map between two value sets is a maintainable asset with a named owner and a version history.
The mistake almost everyone makes
Treating SNOMED CT as if it were a value set. It shows up as "just let them pick any SNOMED code" (an ungoverned free-for-all that produces unanalysable data), and as "map our codes to SNOMED" with no context attached (a project with no finish line). The fix in both cases is the same: name the context, define the value set for it, and do your binding, validation and mapping at the value set level. Once every terminology conversation starts with "which value set?", the scope arguments mostly disappear.
How the three work together in practice
In a working integration, the layers stack cleanly. Value sets are authored and versioned against the code systems they draw from. Fields and message elements are bound to those value sets. At runtime, four terminology operations do the work: $expand materialises a value set into its current list of codes, $validate-code checks an inbound code against the value set it should belong to, $translate applies a concept map when data crosses between contexts, and $lookup fetches a concept's display and properties so humans see words rather than identifiers.
That's the whole machine. A terminology server like WeHub Term exists to host exactly this: the code systems, the value sets built on them, the concept maps between them, and those operations exposed where workflows can call them; local Trust codes are treated with the same machinery as the official standards, because the moment local codes live outside the governance loop, drift begins.
The bottom line
Three concepts, three jobs: the dictionary, the shortlist, the translation. Nearly every terminology problem you'll meet is one of them wearing a disguise. The practical next step costs an afternoon: pick one coded field in one live integration, and write down which code system it draws from, which value set governs it, and which map (if any) touches it in flight. If any of those three answers is "not sure", you've found this quarter's most valuable terminology work.



