One Element, One Binding β and Its Limits
Since FHIR DSTU2, every coded element has had exactly one binding β a rule that ties the element to a set of allowed codes (a ValueSet) with a particular strength. The strength says how strictly the codes must be followed: required means you SHALL use a code from this set; extensible means use one if it applies to your concept, otherwise you may use other codes; preferred and example are progressively looser suggestions. For simple elements like Patient.gender (bound to AdministrativeGender with required strength), this model works perfectly.
But as FHIR adoption grew β across jurisdictions, clinical domains, and regulatory regimes β the one-binding model hit its limits. Profile authors (people who write StructureDefinitions β sets of constraints on top of base FHIR resources) kept running into problems that a single ValueSet couldn't express.
The Extensible+Max Saga
The first workaround was the Extensible+Max pattern. US Core needed a way to say: "use codes from this small ValueSet, but if you must extend, stay within this larger boundary." The solution was the maxValueSet extension, introduced in STU3 and refined in R4.
It immediately caused confusion. The spec described it as "a 'required' binding over the top of the extensible binding" β but no one agreed on what that meant in practice. The core tension, laid bare in a 182-message thread on chat.fhir.org: Argonaut needed "use this code or free text" for ONC compliance β hospitals had free-text problems that were "literally a string in the local system" (Jenni Syed). But no combination of binding strengths could express that. Josh Mandel pointed out that US Core Immunization bound vaccineCode to CVX with both extensible and max β to the same ValueSet: "From an interoperability perspective I can't understand why choosing extensible and maximum is better than just choosing extensible."
Meanwhile, a parallel minValueSet extension tried to set a floor for extensible bindings β if a code from this set applies, you must use it. But it conflated sender constraints with receiver obligations, and validators couldn't enforce it.
Both extensions could only express two narrow use cases, and even those were poorly understood.
The "I Want Multiple Bindings" Problem
At the same time, IG authors kept asking for multiple bindings on a single element. The most common driver was IPS (International Patient Summary), which needed to express a choice of terminology bindings on a CodeableConcept β different code systems for different jurisdictions. The only tool available was slicing β FHIR's mechanism for saying "this repeating element must have entries matching specific patterns." Applied to CodeableConcept.coding, slicing let you require one Coding from SNOMED and another from ICD-10. But it was complex to author, hard for implementers to understand, and verbose in profile rendering.
As Grahame Grieve put it: "There's lots of slicing in Implementation Guides because authors want to say 'one of the codes must be from value set X.' It's the most common use of slicing, and you have to do that because a binding applies to all repeats of the code. But slicing is difficult for implementers."
Grahame's Proposal (February 2022)
In February 2022, Grahame Grieve proposed a new extension on ElementDefinition.binding β additional bindings. The core idea: the main binding stays as the conformance binding (what the validator enforces), but you can attach extra bindings with different purposes:
I would like to define an extension on ElementDefinition.binding that specifies additional bindings. ElementDefinition.binding is the conformance binding: what the validator enforces β and there can only be one. But in addition, designers will be able to specify additional bindings.
His initial purpose list β conformance, required, recommended, UI, starter, component, minimum, maximum β addressed every gap the community had been working around. The motivation:
In a few places we use extensible+max and we mostly really want a base value set with a recommended value set. In a few places we use extensible, and we really want a fairly large base value set with a required β this is what legislation wants for new records.
Rob Hausam immediately saw the value for IPS: "I agree that it looks like this can be a replacement for slicing on CodeableConcept.coding... Assuming that's all true, then when can we start using this in IPS?"
Lloyd McKenzie pushed back: "Generally, if rules are different for different contexts, then you have different profiles." But Grahame countered: "It's no service to users to have myriad profiles that differ only by usage context and some bindings."
By April 2022, the IG Publisher had draft rendering support, and Grahame added the any flag β "if any = true then the binding only applies to one of the repeats, not all of them." By August 2022, IPS was already using it. The feature was committed to the R5 ballot as ElementDefinition.binding.additional, and shipped in R5 (March 2023) as a first-class element β no longer an extension.
How It Works: Semantics First
Before diving into the purpose catalog, two fundamental rules.
Rule 1: all bindings are AND. The main binding and every additional binding apply simultaneously. Lloyd McKenzie stated it plainly: "All bindings always apply. End stop." However, not all bindings bite equally:
- Bindings with a
usagecontext are ignored if you're not in that context - Guidance purposes (
starter,ui,component,preferred) carry no conformance weight currentbindings only apply to data captured since declaring compliance β not to legacy dataextensiblebindings have the standard out: you don't have to comply if no codes in the ValueSet apply to your concept
If you want OR semantics ("send a code from ValueSet A or ValueSet B"), combine them into a single grouped ValueSet. Additional bindings won't give you OR.
For a CodeableConcept β FHIR's datatype that can carry multiple parallel code representations (Codings) of the same concept β multiple required bindings mean you may need multiple Codings, one satisfying each binding. This is how "must send SNOMED AND ICD-10" works without slicing.
Rule 2: the any flag changes repeat semantics. By default, a binding applies to all repetitions of an element. Setting any = true means the binding is satisfied if any one repetition matches. This is the key mechanism that replaces coding slices β and as Lloyd McKenzie noted: "using slicing to do 'and' bindings is now considered an anti-pattern and discouraged."
Structure and Purposes
An additional binding never replaces the main binding β it layers on top. Each has:
| Property | Description |
|---|---|
purpose | Why this binding exists (see tables below) |
valueSet | The ValueSet URL |
documentation | Markdown explaining the use in context |
shortDoco | A brief plain-text summary for tabular rendering |
usage | UsageContext scoping by jurisdiction, domain, or workflow |
any | If true, satisfied when any one repeat matches (default: all must match) |
Here's how it looks in a StructureDefinition (simplified notation):
binding:
strength: extensible
valueSet: http://hl7.org/fhir/ValueSet/observation-codes
additional:
- purpose: starter
valueSet: http://example.org/ValueSet/common-lab-codes
documentation: >
A manageable subset of ~200 common laboratory codes
for implementers getting started.
- purpose: current
valueSet: http://example.org/ValueSet/2026-lab-codes
documentation: >
Required for all new observations captured after 2026-01-01.
Legacy data may use codes outside this set.
The purposes have evolved since Grahame's 2022 proposal (some were renamed, conformance was dropped). Here are the R5 purposes from the AdditionalBindingPurposeCodes ValueSet:
Conformance Purposes
| Purpose | What it means |
|---|---|
required | The element SHALL use a code from this ValueSet β in the specified usage context |
extensible | Use codes from this ValueSet if applicable β in the specified usage context |
current | New records SHALL use this ValueSet. Legacy or externally-sourced data may use other codes |
Guidance Purposes
| Purpose | What it means |
|---|---|
minimum | All conformant applications must accept these codes as valid (application obligation, not instance constraint) |
candidate | May substitute the main ValueSet in documented situations (e.g., a jurisdiction defines a replacement) |
preferred | This ValueSet is preferred in a given context (documentation should explain why) |
ui | Suggested codes for user interface lookup and selection |
starter | A practical subset to start with when the full ValueSet is too large |
component | Documents how a part of the main ValueSet is used (e.g., per code system) |
R6 adds current-extensible (extensible semantics for new data), best-practice (flagged in best-practice validation mode), and open (no restrictions, for documentation).
The maximum purpose exists in R5 but is deprecated in R6. It was originally intended to cap extensible bindings, but its semantics were unclear (see the Extensible+Max saga above). Use required with a usage context instead.
Across FHIR Versions
| Version | How additional bindings work |
|---|---|
| R4 and earlier | Not native. Use the additional-binding extension from the Tooling Extensions IG. The IG Publisher renders them; the validator supports them. The old maxValueSet and minValueSet extensions still work but are superseded. |
| R5 | Native as ElementDefinition.binding.additional. Full validator support. No key element β constraining additional bindings in derived profiles is limited. |
| R6 | Native + key element for constraining across profile layers. New purposes: current-extensible, best-practice, open. maximum deprecated. |
For R4 IGs, additional bindings are expressed as an extension on ElementDefinition.binding:
binding:
strength: extensible
valueSet: http://hl7.org/fhir/ValueSet/observation-codes
extension:
- url: http://hl7.org/fhir/tools/StructureDefinition/additional-binding
extension:
- url: purpose
valueCode: current
- url: valueSet
valueCanonical: http://example.org/ValueSet/2026-codes
- url: documentation
valueMarkdown: Required for new records.
In R5+, the same is expressed natively β no extension wrapper needed.
Scenarios
Multi-Jurisdiction Conformance
An international profile needs different code systems in different countries β SNOMED CT in the US, ICD-10-GM in Germany. Before additional bindings, this meant either separate profiles per jurisdiction or complex slicing. Now you can express it in a single profile using required + any: true + usage:
binding:
strength: extensible
valueSet: http://hl7.org/fhir/ValueSet/condition-code
additional:
- purpose: required
valueSet: http://example.org/ValueSet/us-snomed-conditions
any: true
usage:
- code: { code: US, system: urn:iso:std:iso:3166 }
documentation: US jurisdiction β at least one SNOMED CT coding required.
- purpose: required
valueSet: http://example.org/ValueSet/de-icd10gm-conditions
any: true
usage:
- code: { code: DE, system: urn:iso:std:iso:3166 }
documentation: German jurisdiction β at least one ICD-10-GM coding required.
Three features working together here: required makes the binding enforceable, any: true means "at least one Coding must match" (not all of them β so you can still send other codings alongside), and usage scopes each binding to its jurisdiction. A US system only sees the SNOMED requirement; a German system only sees ICD-10-GM. The main extensible binding applies to both.
Legacy Data Migration
A common problem: a country transitions to a new coding standard, but hospitals have decades of data in the old one. Without additional bindings you'd have to choose β either the binding is loose enough for legacy data (and you lose conformance for new data) or it's strict for new data (and old records fail validation).
Additional bindings solve this with current + minimum:
binding:
strength: extensible
valueSet: http://hl7.org/fhir/ValueSet/condition-code
additional:
- purpose: current
valueSet: http://example.org/ValueSet/icd-11-conditions
documentation: >
All new diagnoses captured after 2026-01-01 must use ICD-11.
- purpose: minimum
valueSet: http://example.org/ValueSet/icd-10-icd-11-conditions
documentation: >
Systems must accept both ICD-10 and ICD-11 codes.
The main binding stays broad (condition-code β extensible). The current binding says: "from now on, use ICD-11." The minimum binding says: "but every conformant system must still accept ICD-10 in incoming data." Neither replaces the main binding β they add precision where the old model had only one knob to turn.
Still Evolving
The mechanism is mature, but the community is still working out edge cases. As recently as late 2025, Eric Haas wrote: "We discussed this topic at the WGM, and as a profiler, I am still confused about how additional bindings are supposed to work." He and Gay Dolin are creating a matrix of explicit use cases with examples for the FHIR Guidance IG. Key areas being refined:
- Conditional bindings β using
usage(UsageContext) to scope bindings by jurisdiction or workflow is powerful but complex in practice (66 messages and counting). - Validator behavior β how violations are reported varies by purpose:
requiredproduces errors, guidance purposes likestarteranduiare informational only.
References and Community Discussions
Spec:
- ElementDefinition.binding.additional β formal definition
- Additional Binding Purpose Codes β all purpose codes with definitions
- Terminologies: Binding Strengths β how strengths work with additional bindings
- Binding Examples β worked examples
- Tooling Extensions IG β R4 backport extension
Community (chat.fhir.org):
- Extension for additional bindings β the original 2022 proposal by Grahame Grieve (49 messages)
- Implementing Additional Bindings for each purpose β AND vs OR semantics, use case matrix (27 messages)
- Conditional additional bindings β UsageContext scoping (66 messages)
- Extensible+Max β the pre-R5 pattern (182 messages)
- Modifications to ElementDefinition β R5 formal commitment (111 messages)




