Un elemento, un binding — y sus limitaciones
Desde FHIR DSTU2, cada elemento codificado ha tenido exactamente un binding — una regla que vincula el elemento a un conjunto de códigos permitidos (un ValueSet) con una determinada fortaleza. La fortaleza indica con qué rigor deben seguirse los códigos: required significa que DEBERÁ utilizarse un código de ese conjunto; extensible significa que se debe usar uno si aplica al concepto en cuestión, aunque se pueden usar otros códigos; preferred y example son sugerencias progresivamente más laxas. Para elementos sencillos como Patient.gender (vinculado a AdministrativeGender con fortaleza required), este modelo funciona a la perfección.
Pero a medida que creció la adopción de FHIR — a través de jurisdicciones, dominios clínicos y marcos regulatorios — el modelo de un único binding alcanzó sus límites. Los autores de perfiles (personas que escriben StructureDefinitions — conjuntos de restricciones sobre los recursos FHIR base) se topaban repetidamente con problemas que un único ValueSet no podía expresar.
La saga de Extensible+Max
El primer recurso fue el patrón Extensible+Max. US Core necesitaba una manera de decir: «use códigos de este pequeño ValueSet, pero si debe extenderlo, permanezca dentro de este límite más amplio». La solución fue la extensión maxValueSet, introducida en STU3 y perfeccionada en R4.
De inmediato generó confusión. La especificación la describía como «un binding "required" sobre el binding extensible» — pero nadie se ponía de acuerdo sobre lo que eso significaba en la práctica. La tensión de fondo quedó al descubierto en un hilo de 182 mensajes en chat.fhir.org: Argonaut necesitaba «use este código o texto libre» para el cumplimiento de ONC — los hospitales tenían problemas con texto libre que era «literalmente una cadena en el sistema local» (Jenni Syed). Pero ninguna combinación de fortalezas de binding podía expresar eso. Josh Mandel señaló que US Core Immunization vinculaba vaccineCode a CVX con tanto extensible como max — al mismo ValueSet: «Desde una perspectiva de interoperabilidad, no entiendo por qué elegir extensible y máximo es mejor que simplemente elegir extensible».
Mientras tanto, una extensión minValueSet paralela intentó establecer un suelo para los bindings extensibles — si un código de ese conjunto aplica, debe usarse. Pero confundía las restricciones del emisor con las obligaciones del receptor, y los validadores no podían aplicarla.
Ambas extensiones solo podían expresar dos casos de uso muy concretos, y ni siquiera esos se comprendían bien.
El problema de «quiero múltiples bindings»
Al mismo tiempo, los autores de IG pedían constantemente múltiples bindings en un mismo elemento. El principal impulsor era IPS (International Patient Summary), que necesitaba expresar una elección de bindings de Terminology en un CodeableConcept — distintos sistemas de códigos para distintas jurisdicciones. La única herramienta disponible era el slicing — el mecanismo de FHIR para indicar que «este elemento repetido debe contener entradas que coincidan con patrones específicos». Aplicado a CodeableConcept.coding, el slicing permitía exigir un Coding de SNOMED y otro de ICD-10. Pero resultaba complejo de crear, difícil de entender para los implementadores y verboso en la representación de perfiles.
Como Grahame Grieve lo expresó: «Hay mucho slicing en las Implementation Guides porque los autores quieren decir "uno de los códigos debe provenir del value set X". Es el uso más frecuente del slicing, y hay que recurrir a él porque un binding se aplica a todas las repeticiones del código. Pero el slicing es difícil para los implementadores».
La propuesta de Grahame (febrero de 2022)
En febrero de 2022, Grahame Grieve propuso una nueva extensión sobre ElementDefinition.binding — bindings adicionales. La idea central: el binding principal se mantiene como binding de conformidad (lo que el validador aplica), pero se pueden adjuntar bindings adicionales con diferentes propósitos:
Me gustaría definir una extensión sobre ElementDefinition.binding que especifique bindings adicionales. ElementDefinition.binding es el binding de conformidad: lo que el validador aplica — y solo puede haber uno. Pero además, los diseñadores podrán especificar bindings adicionales.
Su lista inicial de propósitos — conformance, required, recommended, UI, starter, component, minimum, maximum — abordaba cada una de las carencias con las que la comunidad había estado lidiando. La motivación:
En algunos lugares usamos extensible+max y realmente queremos un value set base con un value set recomendado. En otros usamos extensible, y realmente queremos un value set base bastante amplio con un required — esto es lo que la legislación exige para los registros nuevos.
Rob Hausam vio de inmediato el valor para IPS: «Coincido en que parece que esto puede ser un sustituto del slicing en CodeableConcept.coding... Asumiendo que todo eso es cierto, ¿cuándo podemos empezar a usar esto en IPS?»
Lloyd McKenzie mostró escepticismo: «En general, si las reglas son diferentes para distintos contextos, se tienen diferentes perfiles». Pero Grahame respondió: «No le hace ningún favor a los usuarios tener una multitud de perfiles que solo difieren por el contexto de uso y algunos bindings».
En abril de 2022, el IG Publisher tenía soporte de renderizado en borrador, y Grahame añadió el indicador any — «si any = true, el binding solo aplica a una de las repeticiones, no a todas». En agosto de 2022, IPS ya lo estaba utilizando. La funcionalidad fue incorporada a la votación de R5 como ElementDefinition.binding.additional, y se publicó en R5 (marzo de 2023) como un elemento de primer nivel — ya no como una extensión.
Cómo funciona: la semántica primero
Antes de profundizar en el catálogo de propósitos, dos reglas fundamentales.
Regla 1: todos los bindings son AND. El binding principal y cada binding adicional se aplican simultáneamente. Lloyd McKenzie lo afirmó con claridad: «Todos los bindings se aplican siempre. Punto.» Sin embargo, no todos los bindings tienen el mismo peso:
- Los bindings con un contexto
usagese ignoran si no se está en ese contexto - Los propósitos de orientación (
starter,ui,component,preferred) no tienen peso de conformidad - Los bindings
currentsolo aplican a datos capturados desde la declaración de cumplimiento — no a datos heredados - Los bindings
extensibletienen la salida estándar: no es obligatorio cumplirlos si ningún código del ValueSet aplica al concepto
Si se desea semántica OR («envíe un código del ValueSet A o del ValueSet B»), hay que combinarlos en un único ValueSet agrupado. Los bindings adicionales no proporcionan OR.
Para un CodeableConcept — el tipo de dato de FHIR que puede contener múltiples representaciones paralelas de códigos (Codings) del mismo concepto — múltiples bindings required pueden requerir múltiples Codings, uno que satisfaga cada binding. Así es como funciona «debe enviar SNOMED Y ICD-10» sin necesidad de slicing.
Regla 2: el indicador any cambia la semántica de las repeticiones. Por defecto, un binding se aplica a todas las repeticiones de un elemento. Establecer any = true significa que el binding se satisface si cualquier repetición coincide. Este es el mecanismo clave que reemplaza los slices de coding — y como señaló Lloyd McKenzie aquí: «usar slicing para bindings "and" se considera ahora un antipatrón y se desaconseja».
Estructura y propósitos
Un binding adicional nunca reemplaza al binding principal — se superpone a él. Cada uno tiene:
| Propiedad | Descripción |
|---|---|
purpose | Por qué existe este binding (véanse las tablas a continuación) |
valueSet | La URL del ValueSet |
documentation | Markdown que explica el uso en contexto |
shortDoco | Un breve resumen en texto plano para la representación tabular |
usage | UsageContext delimitado por jurisdicción, dominio o flujo de trabajo |
any | Si es true, se satisface cuando cualquier repetición coincide (por defecto: todas deben coincidir) |
Así es como aparece en una StructureDefinition (notación simplificada):
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.
Los propósitos han evolucionado desde la propuesta de Grahame en 2022 (algunos fueron renombrados, conformance fue eliminado). El elemento purpose tiene un binding required — solo se pueden utilizar códigos del ValueSet AdditionalBindingPurposeCodes; no se permiten propósitos personalizados. Estos son los códigos de R5:
Propósitos de conformidad
| Propósito | Significado |
|---|---|
required | El elemento DEBERÁ usar un código de este ValueSet — en el contexto de uso especificado |
extensible | Use códigos de este ValueSet si aplican — en el contexto de uso especificado |
current | Los registros nuevos DEBERÁN usar este ValueSet. Los datos heredados o procedentes de fuentes externas pueden usar otros códigos |
Propósitos de orientación
| Propósito | Significado |
|---|---|
minimum | Todas las aplicaciones conformes deben aceptar estos códigos como válidos (obligación de la aplicación, no restricción de la instancia) |
candidate | Puede sustituir al binding principal en situaciones documentadas (p. ej., una jurisdicción define un reemplazo) |
preferred | Este ValueSet es preferido en un contexto dado (la documentación debe explicar por qué) |
ui | Códigos sugeridos para la búsqueda y selección en la interfaz de usuario |
starter | Un subconjunto práctico con el que comenzar cuando el ValueSet completo es demasiado extenso |
component | Documenta cómo se usa una parte del ValueSet principal (p. ej., por sistema de códigos) |
R6 añade current-extensible (semántica extensible para datos nuevos), best-practice (marcado en el modo de validación de buenas prácticas) y open (sin restricciones, para documentación).
El propósito maximum existe en R5 pero está obsoleto en R6. Originalmente estaba pensado para limitar los bindings extensibles, pero su semántica era poco clara (véase la saga de Extensible+Max más arriba). Use required con un contexto de uso en su lugar.
A través de las versiones de FHIR
| Versión | Funcionamiento de los bindings adicionales |
|---|---|
| R4 y anteriores | No son nativos. Use la extensión additional-binding del Tooling Extensions IG. El IG Publisher los renderiza; el validador los admite. Las antiguas extensiones maxValueSet y minValueSet siguen funcionando, pero han quedado superadas. |
| R5 | Nativos como ElementDefinition.binding.additional. Soporte completo del validador. Sin elemento key — la restricción de bindings adicionales en perfiles derivados es limitada. |
| R6 | Nativos + elemento key para restringir entre capas de perfiles. Nuevos propósitos: current-extensible, best-practice, open. maximum obsoleto. |
Para IGs en R4, los bindings adicionales se expresan como una extensión sobre 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.
En R5+, lo mismo se expresa de forma nativa — sin necesidad de contenedor de extensión.
Escenarios
Conformidad en múltiples jurisdicciones
Un perfil internacional necesita distintos sistemas de códigos en distintos países — SNOMED CT en EE. UU., ICD-10-GM en Alemania. Antes de los bindings adicionales, esto implicaba perfiles separados por jurisdicción o un slicing complejo. Ahora puede expresarse en un único perfil usando 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.
Tres características trabajando juntas: required hace que el binding sea aplicable, any: true significa «al menos un Coding debe coincidir» (no todos — por lo que se pueden seguir enviando otros codings), y usage delimita cada binding a su jurisdicción. Un sistema estadounidense solo ve el requisito de SNOMED; un sistema alemán solo ve ICD-10-GM. El binding extensible principal se aplica a ambos.
Migración de datos heredados
Un problema habitual: un país hace la transición a un nuevo estándar de codificación, pero los hospitales tienen décadas de datos con el antiguo. Sin bindings adicionales habría que elegir — o el binding es lo suficientemente flexible para los datos heredados (y se pierde la conformidad para los datos nuevos) o es estricto para los datos nuevos (y los registros antiguos no superan la validación).
Los bindings adicionales resuelven esto con 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.
El binding principal sigue siendo amplio (condition-code — extensible). El binding current indica: «a partir de ahora, use ICD-11». El binding minimum indica: «pero todos los sistemas conformes deben seguir aceptando ICD-10 en los datos entrantes». Ninguno reemplaza al binding principal — añaden precisión donde el modelo anterior solo tenía un único parámetro que ajustar.
Bindings dependientes de la categoría (SDOH)
Este es un patrón real de los perfiles US Core SDOH. Condition.code está vinculado a un ValueSet amplio, pero las distintas categorías obtienen bindings más estrictos — si la categoría es food-insecurity, el código debe provenir del VS de Diagnósticos de Inseguridad Alimentaria SDOH; si es housing-instability, de un VS diferente. Cada binding adicional usa usage para delimitar por valor de categoría:
# Condition.code
binding:
strength: required
valueSet: http://hl7.org/fhir/us/core/ValueSet/us-core-condition-code
additional:
- purpose: required
valueSet: http://hl7.org/fhir/us/sdoh/ValueSet/food-insecurity-diagnoses
usage:
- code: { code: food-insecurity, system: http://hl7.org/fhir/us/sdoh/CodeSystem/sdoh-category }
documentation: >
When Condition.category = food-insecurity,
code must come from this ValueSet.
- purpose: required
valueSet: http://hl7.org/fhir/us/sdoh/ValueSet/housing-instability-diagnoses
usage:
- code: { code: housing-instability, system: http://hl7.org/fhir/us/sdoh/CodeSystem/sdoh-category }
documentation: >
When Condition.category = housing-instability,
code must come from this ValueSet.
El contexto usage aquí no es la jurisdicción — es una categoría clínica dentro del mismo recurso. El validador comprueba: si el Condition tiene category = food-insecurity, entonces aplica el binding adicional de inseguridad alimentaria y code debe provenir de ese ValueSet específico. Si la categoría no coincide, el binding se ignora. Como Grahame confirmó: «si su categoría es una de las categorías designadas, entonces aplica el value set de esa categoría».
Sugerencias de interfaz para ValueSets extensos
No todos los bindings adicionales tratan sobre la conformidad. Los propósitos ui y starter no tienen peso de validación — ayudan a los implementadores a construir mejores interfaces. Un perfil de signos vitales puede tener más de 100 000 códigos LOINC en su binding extensible, pero la interfaz solo necesita unos pocos:
# Observation.code (vital signs)
binding:
strength: extensible
valueSet: http://hl7.org/fhir/ValueSet/observation-vitalsignresult
additional:
- purpose: starter
valueSet: http://example.org/ValueSet/common-vitals
documentation: >
15 most common vital sign codes. Start here
if you're building a new system.
- purpose: ui
valueSet: http://example.org/ValueSet/vitals-picker
documentation: >
Curated list optimized for dropdown selection.
Not a conformance constraint.
El propósito starter indica «comience su implementación con estos códigos». El propósito ui indica «muestre estos códigos en un selector». Ninguno afecta a la validación — un sistema puede enviar cualquier código válido según el binding extensible principal. Pero resuelven un problema real: implementadores que se enfrentan a un ValueSet de 100 000 códigos sin saber por dónde empezar.
Sigue evolucionando
El mecanismo está maduro, pero la comunidad sigue resolviendo casos límite. Tan recientemente como a finales de 2025, Eric Haas escribió: «Discutimos este tema en el WGM y, como perfilador, sigo sin entender con claridad cómo se supone que deben funcionar los bindings adicionales». Él y Gay Dolin están creando una matriz de casos de uso explícitos con ejemplos para el FHIR Guidance IG. Áreas clave que se están refinando:
- Bindings condicionales — usar
usage(UsageContext) para delimitar bindings por jurisdicción o flujo de trabajo es poderoso pero complejo en la práctica (66 mensajes y contando). - Comportamiento del validador — la forma en que se notifican las infracciones varía según el propósito:
requiredproduce errores, los propósitos de orientación comostarteryuison solo informativos.
Referencias y debates de la comunidad
Especificación:
- ElementDefinition.binding.additional — definición formal
- Additional Binding Purpose Codes — todos los códigos de propósito con definiciones
- Terminologies: Binding Strengths — cómo funcionan las fortalezas con los bindings adicionales
- Binding Examples — ejemplos desarrollados
- Tooling Extensions IG — extensión de retrocompatibilidad para R4
Comunidad (chat.fhir.org):
- Extension for additional bindings — la propuesta original de 2022 de Grahame Grieve (49 mensajes)
- Implementing Additional Bindings for each purpose — semántica AND frente a OR, matriz de casos de uso (27 mensajes)
- Conditional additional bindings — delimitación por UsageContext (66 mensajes)
- Extensible+Max — el patrón anterior a R5 (182 mensajes)
- Modifications to ElementDefinition — incorporación formal a R5 (111 mensajes)
Véase también: Categorías residuales en FHIR Terminology.

![Terminology is fun: CodeableConcept.coding[]](/assets/images/articles/horizontal-3.avif?v=2nw7.mrp)
