NDC Codes: National Drug Code Standards
Complete guide to National Drug Code (NDC) structure, database design, FDA data integration, drug product identification, and pharmacy dispensing systems.
Abbreviations Used in This Guide
ndc= National Drug Codecd= codedesc= descriptionnbr= numberqty= quantitydt= datedttm= datetimeid= identifierView complete glossary: Pharmacy Abbreviations | Pharmacy Definitions
Table of Contents
1What is NDC?
The National Drug Code (NDC) is a unique product identifier used in the United States for drugs intended for human use. Assigned by the FDA, NDC numbers serve as the universal identifier for prescription and over-the-counter medications.
Key Uses of NDC:
- • Pharmacy dispensing and inventory management
- • Electronic prescribing (eRx) systems
- • Insurance claims processing and reimbursement
- • Drug recall tracking and safety monitoring
- • Pricing and rebate calculations
- • Clinical decision support systems
💡 Example NDC
This NDC identifies: Lipitor (atorvastatin calcium) 40mg tablets, 90-count bottle, manufactured by Pfizer
2NDC Structure & Format
NDC codes consist of 10 or 11 digits divided into three segments, separated by hyphens. The FDA recognizes three format configurations:
Format 1: 4-4-2 (Most Common)
Format 2: 5-3-2
Format 3: 5-4-1
⚠️ 11-Digit NDC Format
For database storage and billing purposes (especially Medicare Part D), NDCs are often stored as 11 digits without hyphens by padding with a leading zero.
3Segment Breakdown
Segment 1: Labeler Code
Definition: Identifies the manufacturer, repackager, or distributor of the drug product. Assigned by the FDA.
Length: 4 or 5 digits
Examples: 0069 (Pfizer), 0002 (Eli Lilly), 0013 (AstraZeneca)
Database Field: ndc_labeler_cd
Note: A single company may have multiple labeler codes for different divisions.
Segment 2: Product Code
Definition: Identifies the specific strength, dosage form, and formulation of the drug.
Length: 3 or 4 digits
Identifies: Drug name, strength, dosage form
Examples: 2587 (Lipitor 40mg tablets), 3000 (Lipitor 10mg tablets)
Database Field: ndc_product_cd
Important: Different strengths of the same drug have different product codes.
Segment 3: Package Code
Definition: Identifies the package size and type.
Length: 1 or 2 digits
Identifies: Package size, unit count, container type
Examples: 10 (90-count bottle), 41 (30-count bottle)
Database Field: ndc_package_cd
Note: The same drug/strength in different package sizes has different package codes.
4Database Design
CREATE TABLE ndc_drugs ( ndc_cd VARCHAR(11) PRIMARY KEY, -- 11-digit format (no hyphens) ndc_formatted VARCHAR(13), -- Display format with hyphens -- NDC Segments ndc_labeler_cd VARCHAR(5) NOT NULL, ndc_product_cd VARCHAR(4) NOT NULL, ndc_package_cd VARCHAR(2) NOT NULL, -- Drug Information drug_nm VARCHAR(500) NOT NULL, generic_nm VARCHAR(500), brand_nm VARCHAR(500), labeler_nm VARCHAR(255), -- Product Details dosage_form VARCHAR(100), -- TABLET, CAPSULE, INJECTION strength VARCHAR(100), -- 40 MG, 500 MG/10 ML route VARCHAR(100), -- ORAL, INTRAVENOUS -- Package Information package_desc VARCHAR(255), package_qty DECIMAL(10,2), package_unit VARCHAR(50), -- EA, ML, GM -- Classification dea_schedule VARCHAR(10), -- C2, C3, C4, C5 (controlled substances) rxcui VARCHAR(20), -- RxNorm concept ID -- Status active_ind CHAR(1) DEFAULT 'Y', marketing_category VARCHAR(50), approval_dt DATE, discontinue_dt DATE, -- Metadata fda_application_nbr VARCHAR(20), created_dttm TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_dttm TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Indexes for performance CREATE INDEX idx_ndc_drugs_labeler ON ndc_drugs(ndc_labeler_cd); CREATE INDEX idx_ndc_drugs_product ON ndc_drugs(ndc_product_cd); CREATE INDEX idx_ndc_drugs_drug_nm ON ndc_drugs(drug_nm); CREATE INDEX idx_ndc_drugs_generic ON ndc_drugs(generic_nm); CREATE INDEX idx_ndc_drugs_active ON ndc_drugs(active_ind); CREATE INDEX idx_ndc_drugs_rxcui ON ndc_drugs(rxcui);
💡 Database Design Best Practices
- • Store 11-digit format: Use ndc_cd as VARCHAR(11) without hyphens for consistency
- • Keep formatted version: Store ndc_formatted separately for display purposes
- • Index all segments: Enable fast lookups by labeler, product, or package
- • Track inactive drugs: Use active_ind flag instead of deleting records
- • Link to RxNorm: rxcui enables clinical decision support integration
- • Update regularly: FDA NDC database changes weekly; schedule updates
5FDA Data Integration
The FDA provides the NDC Directory as a free, downloadable dataset updated weekly. This is the authoritative source for all FDA-registered drug products.
FDA NDC Directory Files:
import pandas as pd
import psycopg2
# Download FDA NDC files
# https://www.fda.gov/drugs/drug-approvals-and-databases/ndc-directory
# Load package.txt (contains NDC codes)
df = pd.read_csv('package.txt', sep='\t', dtype=str)
# Connect to database
conn = psycopg2.connect("dbname=pharmacy user=postgres")
cur = conn.cursor()
# Process each NDC record
for idx, row in df.iterrows():
# Extract NDC (11-digit format)
ndc_11 = row['NDCPACKAGECODE'].replace('-', '').zfill(11)
# Parse segments
labeler = ndc_11[0:5].lstrip('0')
product = ndc_11[5:9].lstrip('0')
package = ndc_11[9:11].lstrip('0')
# Insert into database
cur.execute("""
INSERT INTO ndc_drugs (
ndc_cd, ndc_formatted,
ndc_labeler_cd, ndc_product_cd, ndc_package_cd,
drug_nm, package_desc, active_ind
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (ndc_cd) DO UPDATE SET
updated_dttm = CURRENT_TIMESTAMP
""", (
ndc_11,
row['NDCPACKAGECODE'],
labeler, product, package,
row['PROPRIETARYNAME'],
row['PACKAGEDESCRIPTION'],
'Y' if row['MARKETINGSTATUSNAME'] == 'Active' else 'N'
))
conn.commit()
print(f"Imported {len(df)} NDC records")6NDC Lookup Methods
Method 1: Exact NDC Match
Most reliable method - lookup by complete 11-digit NDC code.
SELECT ndc_formatted, drug_nm, strength, dosage_form, labeler_nm FROM ndc_drugs WHERE ndc_cd = '00069258710' AND active_ind = 'Y';
Method 2: Drug Name Search
Fuzzy search by brand or generic name - useful for user interfaces.
SELECT ndc_cd, drug_nm, strength, dosage_form FROM ndc_drugs WHERE ( drug_nm ILIKE '%lipitor%' OR generic_nm ILIKE '%atorvastatin%' ) AND active_ind = 'Y' ORDER BY drug_nm LIMIT 20;
Method 3: Product Family Lookup
Find all package sizes for a specific drug/strength combination.
SELECT ndc_formatted, package_desc, package_qty, package_unit FROM ndc_drugs WHERE ndc_labeler_cd = '0069' AND ndc_product_cd = '2587' AND active_ind = 'Y' ORDER BY package_qty;
7SQL Query Examples
Find Controlled Substances by DEA Schedule
SELECT ndc_formatted, drug_nm, strength, dea_schedule, labeler_nm FROM ndc_drugs WHERE dea_schedule = 'C2' -- Schedule II (highest control) AND active_ind = 'Y' ORDER BY drug_nm;
List All Strengths of a Generic Drug
SELECT DISTINCT strength, dosage_form, COUNT(*) as package_count FROM ndc_drugs WHERE generic_nm ILIKE '%metformin%' AND dosage_form = 'TABLET' AND active_ind = 'Y' GROUP BY strength, dosage_form ORDER BY CAST(REGEXP_REPLACE(strength, '[^0-9]', '', 'g') AS INTEGER);
Find Recently Discontinued Drugs
SELECT ndc_formatted, drug_nm, labeler_nm, discontinue_dt FROM ndc_drugs WHERE discontinue_dt >= CURRENT_DATE - INTERVAL '90 days' AND discontinue_dt IS NOT NULL ORDER BY discontinue_dt DESC;
8Integration with Dispensing Systems
NDC codes are critical for pharmacy dispensing systems, linking prescriptions to actual drug products and enabling accurate billing, inventory management, and clinical checks.
Common Integration Points:
- • Electronic Prescribing (eRx): Map RxNorm codes to NDC for dispensing
- • Inventory Management: Track stock levels by NDC package code
- • Insurance Claims: Submit NDC in NCPDP D.0 claim format
- • Drug Utilization Review (DUR): Verify correct drug/strength dispensed
- • Pricing: AWP/WAC pricing typically indexed by NDC
CREATE TABLE rx_dispensing ( dispense_id VARCHAR(50) PRIMARY KEY, rx_nbr VARCHAR(50) NOT NULL, patient_id VARCHAR(50) NOT NULL, -- NDC Information ndc_cd VARCHAR(11) NOT NULL, drug_nm VARCHAR(500), qty_dispensed DECIMAL(10,2), days_supply INTEGER, -- Prescription Details prescriber_npi VARCHAR(10), fill_dt DATE NOT NULL, refill_nbr INTEGER, -- Pricing ingredient_cost DECIMAL(10,2), dispensing_fee DECIMAL(10,2), -- References FOREIGN KEY (ndc_cd) REFERENCES ndc_drugs(ndc_cd), created_dttm TIMESTAMP DEFAULT CURRENT_TIMESTAMP );