FHIR Terminology Binding: CodeSystem, ValueSet, ConceptMap
Every code field in FHIR (Condition.code, Observation.code, Patient.gender) is bound to a ValueSet — that is how FHIR guarantees a single unambiguous meaning for each code as it travels between hospitals. ValueSets draw their codes from CodeSystems (ICD-10 VN, SNOMED CT, LOINC), and ConceptMaps translate between coding systems. VN Core is being built on top of more than a dozen CodeSystems tailored to Vietnamese clinical practice.
Audience: developers, vendors, regulators already comfortable with base FHIR who keep hitting "code not in valueset" errors or need to understand why terminology standardization is the make-or-break condition for interoperability.
TL;DR
- CodeSystem is the source-of-truth code set with a canonical URL — for example ICD-10 VN, SNOMED CT, LOINC, or the 54 Vietnamese ethnic groups.
- ValueSet is a composed subset of one or more CodeSystems, used to bind a specific field.
- ConceptMap defines mappings between two coding systems — for example ICD-10 VN to ICD-10 WHO, or XML 4210 to FHIR.
- NamingSystem registers URIs for identifiers (CCCD, BHYT card, BHXH number, hospital MRN), not for clinical codes.
- Binding strength has four levels:
required,extensible,preferred,example— they determine how tightly a ValueSet constrains a field.
On this page
- Four core concepts: CodeSystem, ValueSet, ConceptMap, NamingSystem
- Coding and CodeableConcept: why text always matters
- Binding strength: required, extensible, preferred, example
- ValueSet — composition and expansion
- Operations: $expand, $validate-code, $lookup, $translate
- Terminology server: self-host or use a managed service
- VN Core terminology landscape — 12+ CodeSystems
- When to build your own CodeSystem versus reusing an international standard
- Frequently asked questions
- Further reading
1. Four core concepts
The FHIR Terminology Module (R4 §3.6) splits code-management resources into four buckets: CodeSystem defines the source-of-truth code set, ValueSet selects a usable subset, ConceptMap translates between coding systems, and NamingSystem registers identifier URIs. Understanding this division of labor is a prerequisite for reading any Implementation Guide — US Core, JP Core, or VN Core alike.
CodeSystem — the source-of-truth code set
A CodeSystem is the resource that defines exactly which codes exist and what each one means. Each CodeSystem owns a single globally unique canonical URL that identifies the code set. VN Core uses the convention http://fhir.hl7.org.vn/core/CodeSystem/ with a -cs suffix — for example vn-ethnicity-cs for the catalog of 54 Vietnamese ethnic groups, or vn-icd10-cs for the Vietnamese edition of ICD-10.
{
"resourceType": "CodeSystem",
"url": "http://fhir.hl7.org.vn/core/CodeSystem/vn-ethnicity-cs",
"version": "1.0.0",
"name": "VNEthnicity",
"title": "Dân tộc Việt Nam",
"status": "active",
"content": "complete",
"concept": [
{ "code": "01", "display": "Kinh" },
{ "code": "02", "display": "Tày" },
{ "code": "03", "display": "Thái" }
]
}
The content field signals how complete the resource is: complete (every code is included in the resource), fragment (only part of the system), example (illustrative only), or not-present (only the metadata is defined and the codes live elsewhere — appropriate for very large code sets like SNOMED CT).
ValueSet — the usable subset
A ValueSet introduces no new codes; it carves out a subset of one or more CodeSystems for binding to a field. A single CodeSystem can spawn many different ValueSets depending on context. ICD-10 VN, for example, contains more than 14,000 codes, but a ValueSet for pediatric diagnoses or a ValueSet for communicable diseases will pick just a few hundred relevant codes.
{
"resourceType": "ValueSet",
"url": "http://fhir.hl7.org.vn/core/ValueSet/vn-ethnicity-vs",
"version": "1.0.0",
"name": "VNEthnicityVS",
"status": "active",
"compose": {
"include": [
{
"system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-ethnicity-cs"
}
]
}
}
Note that FHIR R4 makes the status field mandatory (cardinality 1..1) for CodeSystem, ValueSet, ConceptMap, and NamingSystem alike. Forgetting status trips a validator error immediately.
ConceptMap — mapping between two systems
A ConceptMap describes the relationships between codes in two systems. The most common Vietnamese use cases are translating between ICD-10 VN and ICD-10 WHO, or mapping XML 4210 fields (the BHYT data exchange standard) onto FHIR Claim, Coverage, and ExplanationOfBenefit. In R4, sourceUri and targetUri describe the scope of the mapping (typically a ValueSet URL), while group.source and group.target hold the specific CodeSystem URLs.
{
"resourceType": "ConceptMap",
"url": "http://fhir.hl7.org.vn/core/ConceptMap/vn-icd10-to-who",
"version": "1.0.0",
"name": "VNICD10ToWHO",
"status": "active",
"sourceUri": "http://fhir.hl7.org.vn/core/ValueSet/vn-icd10-vs",
"targetUri": "http://hl7.org/fhir/ValueSet/icd-10",
"group": [
{
"source": "http://fhir.hl7.org.vn/core/CodeSystem/vn-icd10-cs",
"target": "http://hl7.org/fhir/sid/icd-10",
"element": [
{
"code": "I10.0",
"target": [
{ "code": "I10", "equivalence": "wider" }
]
}
]
}
]
}
The equivalence field accepts values such as equal, equivalent, wider, narrower, inexact, and unmatched, capturing the degree of semantic equivalence rather than collapsing every relationship into a one-to-one match.
NamingSystem — registering identifier URIs
NamingSystem differs from the other three resources: it does not manage clinical codes but instead registers URIs for identifier systems. The national ID card (CCCD), BHYT card number, BHXH number, and hospital MRN are all identifier systems, and each requires a unique URI so that Patient.identifier can point to it.
{
"resourceType": "NamingSystem",
"name": "VNCCCD",
"status": "active",
"kind": "identifier",
"date": "2026-04-30",
"uniqueId": [
{
"type": "uri",
"value": "http://fhir.hl7.org.vn/core/sid/cccd",
"preferred": true
}
]
}
VN Core's convention is http://fhir.hl7.org.vn/core/sid/{cccd|bhyt|bhxh|gks|passport}. Note that NamingSystem also requires both status and date.
2. Coding and CodeableConcept
These two datatypes cause the most confusion for newcomers to FHIR. Coding represents a single code with system, version, code, and display. CodeableConcept wraps an array of equivalent Coding entries together with a free-text text field that captures the human-readable description.
"code": {
"coding": [
{
"system": "http://hl7.org/fhir/sid/icd-10",
"version": "2019",
"code": "I10",
"display": "Essential hypertension"
},
{
"system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-icd10-cs",
"code": "I10.0",
"display": "Tăng huyết áp vô căn"
}
],
"text": "Tăng huyết áp"
}
The same diagnosis can be coded in parallel with both ICD-10 WHO and ICD-10 VN. HL7's strongest best practice is unambiguous: always populate the text field, even when several coding entries are present. The reason is twofold. First, the Vietnamese-language description a clinician types into the EMR rarely matches the canonical display of a code exactly. Second, when a code is later deprecated, the text field preserves the original intent of the author.
Pragmatic rule: if you can only fill in one of the two, choose CodeableConcept. The text field outlasts every code-set revision, while coding is what makes the data machine-readable.
3. Binding strength: four levels of constraint
When a FHIR field is bound to a ValueSet, implementers need to know how strictly the binding applies. HL7 R4 defines four levels on the Terminology — Binding page (hl7.org/fhir/R4/terminologies.html#strength):
| Strength | Meaning | FHIR R4 base example |
|---|---|---|
required | The code must come from the ValueSet. Validators flag anything outside it as an error. Text-only is not allowed. | Patient.gender bound to AdministrativeGender (male/female/other/unknown). |
extensible | If the concept is already in the ValueSet, you must use that code. You may extend with codes outside the set only when no listed concept covers what you need to record. | Patient.maritalStatus is bound extensible to MaritalStatus. Downstream profiles may tighten this further. |
preferred | Using the ValueSet is recommended but not required. Validators only emit a warning. | Encounter.serviceType is bound preferred to ServiceType. |
example | The ValueSet is purely illustrative. There is no binding obligation at all. | Condition.code in R4 base is bound example to Condition/Problem/Diagnosis Codes. |
A profile such as VN Core is free to tighten the binding strength inherited from base. Where R4 base binds Condition.code at example strength, VN Core may re-profile it to extensible against an ICD-10 VN ValueSet, forcing systems to prefer ICD-10 VN codes whenever a suitable one exists.
Important: extensible is stricter than preferred. If the concept that needs to be recorded does appear in the ValueSet but the user fills in a different code or only text, the validator raises an error. preferred is purely advisory — there is no enforcement mechanism behind it.
4. ValueSet — composition and expansion
ValueSets have two faces: composition (the rules for selection) and expansion (the resulting flat list of actual codes).
Composition — the definition
The compose section of a ValueSet lists the rules for picking codes: include selects sets, exclude removes them. Selection can be driven by filter on CodeSystem properties — for example all descendants of a parent code, or all codes with status = active.
ValueSet: VNEncounterTypeVS
Id: vn-encounter-type-vs
Title: "Loại lượt khám"
Description: "Phân loại lượt khám theo TT 13/2025/TT-BYT"
* ^status = #active
* include codes from system VNEncounterTypeCS where status = #active Expansion — the result
When a terminology server expands a ValueSet (via the $expand operation), the result is a flat list of actual codes:
{
"resourceType": "ValueSet",
"url": "http://fhir.hl7.org.vn/core/ValueSet/vn-encounter-type-vs",
"status": "active",
"expansion": {
"timestamp": "2026-04-30T10:00:00+07:00",
"contains": [
{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-encounter-type-cs", "code": "OUTPATIENT", "display": "Ngoại trú" },
{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-encounter-type-cs", "code": "INPATIENT", "display": "Nội trú" },
{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-encounter-type-cs", "code": "EMERGENCY", "display": "Cấp cứu" }
]
}
} Separating composition from expansion is a deliberate design choice: composition stays stable inside the IG, while expansion can be recomputed by a terminology server at any time when the underlying CodeSystem changes. A ValueSet of diagnoses defined as "all ICD-10 VN codes with status=active" automatically picks up new codes as soon as the Ministry of Health issues an additional decision.
5. Operations: $expand, $validate-code, $lookup, $translate
FHIR specifies five core terminology operations that every conformant terminology server must support:
$expandon ValueSet — returns the flat list of codes. Supports filtering, paging, and language selection.$validate-codeon ValueSet or CodeSystem — checks whether a given code is valid in the requested context.$lookupon CodeSystem — retrieves the display value, multilingual designations, and properties of a code.$translateon ConceptMap — applies a mapping to translate a code from one system to another.$subsumeson CodeSystem — tests the parent-child (subsumption) relationship between two codes.
GET /ValueSet/vn-ethnicity-vs/$expand
GET /CodeSystem/vn-icd10-cs/$lookup?code=I10.0
GET /CodeSystem/vn-icd10-cs/$validate-code?code=I10.0
POST /ConceptMap/vn-icd10-to-who/$translate?code=I10.0&system=http://fhir.hl7.org.vn/core/CodeSystem/vn-icd10-cs
In real EMR deployments, validators typically call $validate-code every time a clinician picks a code from a dropdown; the UI calls $expand to populate that dropdown; and the BHYT integration gateway can call $translate to convert internal ICD-10 VN codes into the format BHXH (Vietnam Social Security) accepts.
6. Terminology server
A terminology server is the dedicated service that handles those operations. The most common options:
- Ontoserver (CSIRO, Australia) — a mature commercial product, strong on SNOMED CT, used in AU Core and the NHS.
- HAPI FHIR JPA Server — open source, ships with a complete terminology module, well suited for in-country deployments.
- Snowstorm (SNOMED International) — open source, purpose-built for SNOMED CT.
- tx.fhir.org — the public terminology server operated by HL7, used for testing and IG validation.
The current direction for VN Core is to rely on tx.fhir.org during the early phase for testing while planning a self-hosted instance at terminology.hl7.org.vn to satisfy data residency requirements set by the Cybersecurity Law (Law 24/2018/QH14) and the Personal Data Protection Law (Law 91/2025/QH15). This is a reference model — the concrete infrastructure design will be published once finalized.
7. VN Core terminology landscape
The VN Core terminology stack is organized along two axes: reusing international standards (ICD-10, LOINC, SNOMED CT) and building Vietnam-specific CodeSystems (ethnicity, BHYT, administrative divisions, hospital tiers). Every code in a CodeSystem is paired with a specific legal citation (Circular, Decision, or Decree) — a hard requirement codified in CONTRIBUTING.
| Code set | CodeSystem ID | Code count | Vietnam legal reference |
|---|---|---|---|
| ICD-10 VN | vn-icd10-cs | ~14,000 | Decision 4469/QĐ-BYT (28/10/2020) |
| ICD-10 COVID-19 | vn-icd10-covid-cs | 2 (U07.1, U07.2) | Decision 98/QĐ-BYT (14/01/2022) |
| ICD-9-CM 2026 | vn-icd9cm-cs | ~3,000 | Decision 387/QĐ-BYT (05/02/2026) |
| Vietnamese ethnic groups | vn-ethnicity-cs | 54 | General Statistics Office |
| Administrative divisions | vn-admin-division-cs | ~3,355 (34 provinces + 3,321 communes) | Decision 19/2025/QĐ-TTg (Resolution 202/2025/QH15) |
| BHYT subject categories | vn-bhyt-subject-cs | ~30 | Decision 3276/QĐ-BYT (17/10/2025) |
| Care tier (2-tier model) | vn-kcb-line-cs | 3 (Central / Provincial / Commune) | Resolution 202/2025/QH15 |
| Healthcare facility rank | vn-hospital-rank-cs | 4 ranks | Circular 06/2024/TT-BYT (16/05/2024) |
| LOINC partial (paraclinical batch 1) | vn-loinc-cs | 2,964 | Decision 1227/QĐ-BYT (11/04/2025) |
| SNOMED CT VN batches 1-3 | vn-snomed-ct-cs | Several thousand concepts | Decision 2427/QĐ-BYT (25/07/2025), Decision 2493/QĐ-BYT (08/2025), Decision 2805/QĐ-BYT (04/09/2025) |
| Traditional Vietnamese medicine terminology | vn-yhct-cs | Several thousand terms | Decision 2552/QĐ-BYT (12/08/2025), Decision 3080/QĐ-BYT (26/09/2025) |
| Legal-document reference list | vn-legal-doc-ref-cs | 101 entries | Compiled and maintained by the VN Core project |
ICD-10 VN diverges from the WHO baseline mainly in that Vietnam has expanded the four- and five-character branches for several locally common diseases — for example I10.0 (essential hypertension) and I10.1, where WHO retains only I10. Consequently, the ConceptMap from ICD-10 VN to ICD-10 WHO is most often a wider relationship: the VN code is narrower, and its WHO parent is broader.
SNOMED CT raises a separate licensing question. Vietnam is not yet a SNOMED International member, so the three Decisions 2427, 2493, and 2805 only publish mapping codes — they do not, by themselves, grant the right to use the full SNOMED CT distribution. Organizations that need the complete SNOMED CT release still have to negotiate either national membership or a separate affiliate license.
8. When to build your own CodeSystem
A common mistake in greenfield projects is to mint a custom CodeSystem for everything, which fragments terminology and destroys interoperability. The HL7 Vocabulary Working Group's general rule:
Do not roll your own when
- A suitable international standard already exists (ICD-10, LOINC, SNOMED CT, ATC, ISO 3166).
- FHIR core or terminology.hl7.org already covers the concept (AdministrativeGender, MaritalStatus, ContactPointSystem).
- A strong regional IG (US Core, JP Core) already defines a reusable CodeSystem.
Do build your own when
- The concept is Vietnam-specific: 54 ethnic groups, BHYT subject categories, care tiers under Resolution 202/2025, hospital ranks per Circular 06/2024.
- A specific Vietnamese legal instrument issues a code list (Ministry of Health Decision, Ministry of Health Circular, General Statistics Office Decision).
- The international code set lacks granular branches that Vietnamese practice requires (for example, ICD-10 VN expanding beyond ICD-10 WHO).
- You need a CodeSystem internal to the IG (for example,
VNLegalDocumentRefCSfor citing legal documents from profiles and extensions).
Once you commit to building your own, three hard rules apply:
- Every code must carry a specific legal citation in a concept property or designation, so that it traces back to the originating Circular or Decision.
- Versioning must be explicit: when the underlying legal instrument changes, increment the CodeSystem version and mark superseded codes with
status = deprecatedor aretirement-date. - The canonical URL pattern
http://fhir.hl7.org.vn/core/CodeSystem/vn-{domain}-csis immutable.
9. Frequently asked questions
Can a single field be bound to several ValueSets at once?
FHIR R4 allows only one primary binding per element. However, because CodeableConcept.coding is an array, a single field can carry multiple Coding entries from different CodeSystems, as long as they all express the same concept. This is the standard mechanism for coding a Condition.code with both ICD-10 VN and SNOMED CT simultaneously.
Where does ICD-10 VN diverge from ICD-10 WHO?
ICD-10 VN — issued under Decision 4469/QĐ-BYT (28/10/2020) — extends four- and five-character classifications for a number of diseases that are particularly prevalent in Vietnam, and adds the COVID-19 codes (U07.1, U07.2) via Decision 98/QĐ-BYT. The three-character codes line up almost exactly with WHO; the divergence appears only at finer granularity.
Is a SNOMED CT license mandatory?
Vietnam is not yet a SNOMED International member, so there is no nationwide right to use SNOMED CT in full. The three 2025 Decisions (2427, 2493, 2805) issue VN-to-SNOMED CT mappings for selected branches only (Body Structure, Morphologic Abnormality, Allergy plus Finding). Organizations that want to deploy SNOMED CT in its entirety must negotiate a separate affiliate license with SNOMED International.
Can NamingSystem stand in for CodeSystem?
No. NamingSystem only registers URIs for identifier systems (CCCD, BHYT, BHXH, MRN); it does not manage clinical codes. Conflating the two is a common source of validator errors: Patient.identifier.system must be a URI registered through a NamingSystem, while Condition.code.coding.system must point to the canonical URL of a CodeSystem.
References
- HL7 FHIR R4 — Terminology Module: hl7.org/fhir/R4/terminology-module.html
- HL7 FHIR R4 — Binding strength: hl7.org/fhir/R4/terminologies.html#strength
- HL7 FHIR R4 — CodeSystem definitions: hl7.org/fhir/R4/codesystem-definitions.html
- HL7 FHIR R4 — ValueSet definitions: hl7.org/fhir/R4/valueset-definitions.html
- HL7 FHIR R4 — ConceptMap definitions: hl7.org/fhir/R4/conceptmap-definitions.html
- HL7 FHIR R4 — NamingSystem definitions: hl7.org/fhir/R4/namingsystem-definitions.html
- Decision 4469/QĐ-BYT (28/10/2020) — Vietnamese edition of ICD-10.
- Decision 98/QĐ-BYT (14/01/2022) — Adding COVID-19 codes to ICD-10 VN.
- Decision 1227/QĐ-BYT (11/04/2025) — Paraclinical indicator code list, batch 1 (LOINC mapping).
- Decision 2427/QĐ-BYT (25/07/2025) — SNOMED CT VN batch 1, Body Structure.
- Decision 2493/QĐ-BYT (08/2025) — SNOMED CT VN batch 2, Morphologic Abnormality.
- Decision 2805/QĐ-BYT (04/09/2025) — SNOMED CT VN batch 3, Allergy and Finding.
- Decision 387/QĐ-BYT (05/02/2026) — ICD-9-CM 2026 classification.
- Resolution 202/2025/QH15 (12/06/2025) — Reorganization of provincial-level administrative units.
- Circular 06/2024/TT-BYT (16/05/2024) — Healthcare facility ranks (4 tiers).
- Snowstorm SNOMED CT terminology server: github.com/IHTSDO/snowstorm
- Ontoserver (CSIRO): ontoserver.csiro.au