The TX module provides FHIR terminology services for CodeSystem, ValueSet, and ConceptMap resources. It supports multiple endpoints at different FHIR versions, all backed by a shared terminology library. It is the reference terminology server for the FHIR community and the FHIR terminology ecosystem.
- Improve batch support
Unlike other modules in this server that mount at a single path (e.g., /shl, /packages), the TX module registers multiple endpoints directly at the root level. Each endpoint is configured with its own path, FHIR version, and optional context string.
When a request arrives at an endpoint, the module:
- Creates a Provider instance from the shared Library using the configured FHIR version and context
- Passes the Provider to the appropriate worker to handle the operation
- Returns the FHIR-compliant response
Add the tx section to your config.json:
{
"modules": {
"tx": {
"enabled": true,
"librarySource": "/path/to/library.yml",
"cacheTimeout": 30,
"internalLimit" : 10000,
"externalLimit" : 1000,
"expansionCacheSize": 1000,
"expansionCacheMemoryThreshold": 0,
"endpoints": [
{
"path": "/tx/r5",
"fhirVersion": "5.0",
"context": null
},
{
"path": "/tx/r4",
"fhirVersion": "4.0",
"context": null
},
{
"path": "/tx/r3",
"fhirVersion": "3.0",
"context": null
},
{
"path": "/tx/r4/demo",
"fhirVersion": "4.0",
"context": "demo"
}
]
}
}
}| Option | Type | Required | Description |
|---|---|---|---|
enabled |
boolean | Yes | Whether the module is enabled |
cacheTimeout |
integer | No | How many minutes to keep client side caches (for cache-id parameter). Default: 30 |
expansionCacheSize |
integer | No | Maximum number of expanded ValueSets to cache. Default: 1000 |
expansionCacheMemoryThreshold |
integer | No | Heap memory usage in MB that triggers evicting oldest half of expansion cache. 0 = disabled. Default: 0 |
librarySource |
string | Yes | Path to the YAML file that defines the terminology sources to load |
internalLimit |
integer | No | Largest number of codes in internal expansions |
externalLimit |
integer | No | Largest number of codes the server will return in an expansion |
endpoints |
array | Yes | List of endpoint configurations (at least one required) |
Each endpoint in the endpoints array has:
| Option | Type | Required | Description |
|---|---|---|---|
path |
string | Yes | The URL path where this endpoint will be mounted (e.g., /tx/r4) |
fhirVersion |
number | Yes | FHIR version: 3 (STU3), 4 (R4), 5 (R5), or 6 (R6) |
context |
string | No | Optional context string passed to the Library when creating Providers |
Note: Endpoint paths must be unique. The module will throw an error if duplicate paths are configured or if a path conflicts with another module.
Each endpoint provides the following FHIR terminology operations:
| Operation | Endpoints | Methods |
|---|---|---|
| Read | GET /{path}/CodeSystem/{id} |
GET |
| Search | GET /{path}/CodeSystem?{params} |
GET, POST |
| $lookup | GET/POST /{path}/CodeSystem/$lookup |
GET, POST |
| $lookup (instance) | GET/POST /{path}/CodeSystem/{id}/$lookup |
GET, POST |
| $validate-code | GET/POST /{path}/CodeSystem/$validate-code |
GET, POST |
| $validate-code (instance) | GET/POST /{path}/CodeSystem/{id}/$validate-code |
GET, POST |
| $subsumes | GET/POST /{path}/CodeSystem/$subsumes |
GET, POST |
| $subsumes (instance) | GET/POST /{path}/CodeSystem/{id}/$subsumes |
GET, POST |
| Operation | Endpoints | Methods |
|---|---|---|
| Read | GET /{path}/ValueSet/{id} |
GET |
| Search | GET /{path}/ValueSet?{params} |
GET, POST |
| $expand | GET/POST /{path}/ValueSet/$expand |
GET, POST |
| $expand (instance) | GET/POST /{path}/ValueSet/{id}/$expand |
GET, POST |
| $validate-code | GET/POST /{path}/ValueSet/$validate-code |
GET, POST |
| $validate-code (instance) | GET/POST /{path}/ValueSet/{id}/$validate-code |
GET, POST |
| Operation | Endpoints | Methods |
|---|---|---|
| Read | GET /{path}/ConceptMap/{id} |
GET |
| Search | GET /{path}/ConceptMap?{params} |
GET, POST |
| $translate | GET/POST /{path}/ConceptMap/$translate |
GET, POST |
| $translate (instance) | GET/POST /{path}/ConceptMap/{id}/$translate |
GET, POST |
| $closure | GET/POST /{path}/ConceptMap/$closure |
GET, POST |
Each endpoint also provides:
GET /{path}/metadata- Returns a CapabilityStatement describing the endpoint's capabilitiesGET /{path}/- Returns basic endpoint information
The library - the source to load - is configured using a YAML file.
base:
url: https://example.com/terminology-files
sources:
- internal:lang
- ucum:tx/data/ucum-essence.xml
- snomed!:sct_intl_20250201.cache
- npm:hl7.terminology| Option | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Base URL for downloading external terminology files. Files specified in sources (for types that require downloads) will be fetched from this URL if not already cached locally. |
The idea here is that the configuration file is probably in a git repo somewhere, but lots of the content it points to isn't and can't or shouldn't be - too big. Note that that files in the list below are considered to never change once they are created.
Each source entry follows the format:
type[!]:details
- type: The source type (see Source Types below)
- ! (optional): Append to type to mark this source as the default for its code system. When multiple versions of the same code system are loaded, the default is used when no version is specified.
- details: Type-specific configuration (filename, package name, or internal provider name)
Built-in code system providers that are compiled into the server. These don't require external files.
- internal:lang # IETF BCP-47 language codes
- internal:country # ISO 3166 country codes
- internal:currency # ISO 4217 currency codes
- internal:areacode # Telephone area codes
- internal:mimetypes # MIME types
- internal:usstates # US state codes
- internal:hgvs # HGVS (Human Genome Variation Society) nomenclatureNote: The ! default marker is not supported for internal providers.
Loads UCUM from a local XML file (ucum-essence format).
- ucum:tx/data/ucum-essence.xmlThe path is relative to the server's base directory. The UCUM essence XML file can be obtained from https://ucum.org.
Loads LOINC from a SQLite database file.
- loinc:loinc-2.81-b.dbThe filename is downloaded from the base URL if not cached. Database files must be in the server's proprietary format. The file is built by importing LOINC (see documentation)
Loads RxNorm drug terminology from a SQLite database file.
- rxnorm:rxnorm_02032025-a.dbThe file is built by importing RxNorm (see documentation)
Loads NDC codes from a SQLite database file.
- ndc:ndc-20211101.dbLoads FDA UNII codes from a SQLite database file.
- unii:unii_20240622.dbThe file is built by importing UNII (see documentation)
Loads SNOMED CT from a cache file. Multiple editions and versions can be loaded simultaneously.
- snomed!:sct_intl_20250201.cache # International edition (default)
- snomed:sct_intl_20240201.cache # Older international edition
- snomed:sct_us_20250901.cache # US edition
- snomed:sct_au_20230731.cache # Australian edition
- snomed:sct_uk_20230412.cache # UK editionCommon edition identifiers:
intl- Internationalus- United Statesau- Australiauk- United Kingdomse- Swedenbe- Belgiumch- Switzerlanddk- Denmarknl- Netherlandsips- IPS (International Patient Summary) Free Set
The file is built by importing SNOMED CT (see documentation)
Loads CPT codes from a SQLite database file.
- cpt:cpt-2023-fragment-0.1.dbNote: CPT is copyrighted by the American Medical Association. Ensure you have appropriate licensing.
The file is built by importing CPT (see documentation)
Loads OMOP (Observational Medical Outcomes Partnership) vocabulary mappings from a SQLite database file.
- omop:omop_v20250227.dbThe file is built by importing OMOP (see documentation)
Loads CodeSystem, ValueSet, and ConceptMap resources from FHIR NPM packages. Packages are fetched from the FHIR package registry (packages2.fhir.org).
- npm:hl7.terminology # HL7 Terminology (THO)
- npm:fhir.tx.support.r4 # TX support package
- npm:ihe.formatcode.fhir # IHE format codes
- npm:fhir.dicom # DICOM terminology
- npm:hl7.fhir.us.core # US Core profiles
- npm:us.nlm.vsac # VSAC value sets
- npm:us.cdc.phinvads # CDC PHIN VADS
- npm:hl7.fhir.uv.sdc # Structured Data CaptureYou can specify a version using the # syntax:
- npm:hl7.terminology#5.0.0
- npm:hl7.fhir.us.core#6.1.0If no version is specified, the latest released version is fetched.
Loads a FHIR package directly from a tarball URL instead of the FHIR package registry. Useful for packages hosted on CI build servers, branches, or other locations.
Use url/cs to load only CodeSystem resources from the package (same as npm/cs).
# Load a package from a CI build server
- url:https://example.com/my-package/package.tgz
# Load a code-systems-only package from a URL
- url/cs:https://example.com/my-codesystems/package.tgzThe URL must point to a .tgz file in standard FHIR NPM package format. Downloaded packages are cached locally by URL.
When multiple versions of the same code system are loaded, append ! to mark one as the default:
- snomed!:sct_intl_20250201.cache # This is the default SNOMED CT
- snomed:sct_intl_20240201.cache # Also available, but not defaultWhen a terminology operation doesn't specify a version, the default version is used. Only one source per code system should be marked as default.
Files specified in sources (except internal and ucum) are:
- First checked in the local cache folder (
terminology-cache) - Downloaded from the
base.urlif not present - Cached locally for future use
NPM packages are handled separately through the FHIR package registry.
Here's a complete example for a production terminology server:
base:
url: https://storage.googleapis.com/tx-fhir-org
sources:
# Built-in code systems
- internal:lang
- internal:country
- internal:currency
- internal:mimetypes
# Units of measure
- ucum:tx/data/ucum-essence.xml
# Clinical terminologies
- loinc:loinc-2.81-b.db
- rxnorm:rxnorm_02032025-a.db
- snomed!:sct_intl_20250201.cache
- snomed:sct_us_20250901.cache
# FHIR packages
- npm:hl7.terminology
- npm:hl7.fhir.us.core
- npm:us.nlm.vsacAlso see tx.fhir.org.yml for the production configuration for tx.fhir.org
┌─────────────────────────────────────────────────────────────┐
│ Library │
│ (Loaded once at startup from YAML) │
│ - Code System Factories │
│ - Code System Providers │
│ - Value Set Providers │
└─────────────────────────────────────────────────────────────┘
│
│ cloneWithFhirVersion(version, context)
▼
┌─────────────────────────────────────────────────────────────┐
│ Provider │
│ (Created per-request with FHIR version context) │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ /tx/r5 │ │ /tx/r4 │ │ /tx/r3 │
│ FHIR R5 │ │ FHIR R4 │ │ FHIR R3 │
└──────────┘ └──────────┘ └──────────┘
The module uses worker classes to handle specific operations:
| Worker | Operations |
|---|---|
read.js |
Resource read operations |
search.js |
Resource search operations |
lookup.js |
CodeSystem $lookup |
subsumes.js |
CodeSystem $subsumes |
validate.js |
CodeSystem and ValueSet $validate-code |
expand.js |
ValueSet $expand |
translate.js |
ConceptMap $translate |
closure.js |
ConceptMap $closure |
All errors are returned as FHIR OperationOutcome resources:
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "not-found",
"diagnostics": "CodeSystem/example not found"
}]
}- Write operations (PUT, POST, DELETE, PATCH) on resources are not supported and return 405 Method Not Allowed
- The Library is loaded once at startup; changes to the YAML source require a server restart
- Each endpoint has it's own Provider instance
