Drug interaction checking is a foundational capability in any clinical or formulary management system. When a patient is prescribed a new medication, the system needs to evaluate that drug against the patient's existing medications and flag potentially dangerous combinations. RxNorm from the National Library of Medicine provides the authoritative drug naming and relationship data needed to build this capability.

Update (January 2024): NLM retired the RxNorm interaction API endpoints (/interaction/) on January 2, 2024. The drug name resolution, NDC mapping, and relationship endpoints described below remain fully active. For interaction checking, NLM recommends using the downloadable RxNorm dataset (updated monthly) with a local database, or integrating with alternative sources such as the DrugBank API or openFDA adverse event data. The architectural patterns in this article remain applicable to local RxNorm deployments.

Understanding RxNorm's Data Model

RxNorm is not just a drug dictionary. It is a normalized naming system that maps between all the different ways drugs are identified across the healthcare ecosystem. An NDC (National Drug Code) identifies a specific packaged product. A brand name identifies a marketing authorization. An RxCUI (RxNorm Concept Unique Identifier) is the canonical identifier that ties them all together.

The key concept types in RxNorm are:

For interaction checking, you typically work at the ingredient (IN) level, because interactions are between active substances regardless of brand, strength, or formulation.

The RxNorm API

The RxNorm REST API is hosted at https://rxnav.nlm.nih.gov/REST/. It is free, requires no API key, and has no published rate limits (though NLM asks that you be reasonable). The key endpoints for drug resolution are:

# 1. Look up an RxCUI by drug name
GET /rxcui.json?name=atorvastatin
# Returns: {"idGroup": {"rxnormId": ["83367"]}}

# 2. Get drug class information
GET /rxclass/class/byDrugName.json?drugName=atorvastatin
# Returns drug class memberships (ATC, VA, MESH, etc.)

# 3. Get related drugs by ingredient
GET /rxcui/83367/related.json?tty=IN+SCD+SBD
# Returns related concepts by term type

Note: The interaction endpoints (/interaction/interaction.json and /interaction/list.json) shown in earlier versions of this guide were retired by NLM on January 2, 2024. For production interaction checking, use a local RxNorm database or the DrugBank API. The drug resolution endpoints above remain active.

Resolving Drug Names to RxCUIs

The first challenge in building an interaction checker is resolving the various ways drugs are identified into RxCUIs. Users might enter brand names, generic names, or NDCs. RxNorm provides multiple lookup methods:

import requests

RXNORM_BASE = "https://rxnav.nlm.nih.gov/REST"

def resolve_to_rxcui(drug_input):
    """Resolve a drug name or NDC to an RxCUI."""

    # Try exact name match first
    resp = requests.get(f"{RXNORM_BASE}/rxcui.json",
                        params={"name": drug_input})
    data = resp.json()
    ids = data.get("idGroup", {}).get("rxnormId", [])
    if ids:
        return ids[0]

    # Try approximate match
    resp = requests.get(f"{RXNORM_BASE}/approximateTerm.json",
                        params={"term": drug_input, "maxEntries": 5})
    data = resp.json()
    candidates = data.get("approximateGroup", {}).get("candidate", [])
    if candidates:
        return candidates[0]["rxcui"]

    # Try NDC lookup
    resp = requests.get(f"{RXNORM_BASE}/ndcstatus.json",
                        params={"ndc": drug_input})
    data = resp.json()
    status = data.get("ndcStatus", {})
    if status.get("rxcui"):
        return status["rxcui"]

    return None

Checking Pairwise Interactions

Once you have RxCUIs, the interaction API does the heavy lifting:

def check_interactions(rxcui_list):
    """Check all pairwise interactions among a list of RxCUIs."""
    rxcuis_param = "+".join(rxcui_list)
    resp = requests.get(
        f"{RXNORM_BASE}/interaction/list.json",
        params={"rxcuis": rxcuis_param}
    )
    data = resp.json()

    interactions = []
    for group in data.get("fullInteractionTypeGroup", []):
        source = group.get("sourceName", "")
        for itype in group.get("fullInteractionType", []):
            for pair in itype.get("interactionPair", []):
                interactions.append({
                    "source": source,
                    "severity": pair.get("severity", "N/A"),
                    "description": pair.get("description", ""),
                    "drugs": [
                        c.get("minConceptItem", {}).get("name", "")
                        for c in pair.get("interactionConcept", [])
                    ]
                })
    return interactions

Interaction Data Sources

Drug interaction data is available from multiple sources. When the RxNorm interaction API was active, it aggregated from two primary sources that remain independently available:

For a formulary management system, you typically want both sources. DrugBank provides breadth, while ONCHigh flags the interactions that clinical teams consider most critical for patient safety alerts.

Production Architecture Considerations

Batch Pre-computation

For a formulary system, you can pre-compute interactions for your entire formulary during the weekly data refresh cycle rather than checking them on demand. A formulary of 5,000 NDCs might map to 800 unique ingredients, resulting in roughly 320,000 pairwise checks. With the RxNorm list endpoint handling batches, this is feasible as a nightly job.

Local Database Mirror

NLM publishes the full RxNorm dataset as a downloadable file (updated monthly). For production systems with high query volumes, running a local copy eliminates API dependency and latency. The full dataset is roughly 300MB and can be loaded into PostgreSQL or similar.

Severity Classification

Raw interaction data needs clinical interpretation. We recommend a three-tier severity model for formulary management applications:

RxNorm's free drug resolution data, combined with interaction data from DrugBank or a locally hosted RxNorm database, gives healthcare technology teams a solid foundation for drug interaction checking. For teams building formulary management or clinical decision support systems, the RxNorm naming and relationship data remains one of the highest-value free resources available, even with the retirement of the hosted interaction endpoints.