NADAC Weekly Drug Prices
Description
The National Average Drug Acquisition Cost (NADAC) is the price US retail pharmacies actually pay for each drug, surveyed by CMS and published every week as a file of about 30,000 National Drug Codes (NDCs). It is the closest public series to a wholesale generic drug price index in the United States.
This product is the weekly series as a panel: one row per NDC per week, with the prior week's price and week-over-week change, the price 52 weeks earlier and year-over-year change, a flag for whether the price was repriced that week, the FDA labeler of record, and a stock ticker where the labeler is a listed company. A second table is a weekly generic deflation index: median and mean week-over-week and year-over-year change across all generic NDCs, the share of NDCs falling, rising and unchanged, the number repriced, and a chained index level.
How the weekly file behaves, and why it matters for reading the data. Each
weekly file is a full snapshot. week_date is the file date. effective_date
is when the current price took effect and only moves when CMS reprices. CMS
reprices the whole file roughly monthly (about 27,000 NDCs move on a reprice
week, dozens otherwise), so the weekly median week-over-week change is zero in
about three weeks out of four. Read yoy_change_pct, or share_falling and
n_repriced on reprice weeks, or a four-week roll of wow_change_pct.
- Source: CMS NADAC weekly files via the yearly datasets on
data.medicaid.gov; FDA National Drug Code Directory (current products and
the excluded-products file) for labeler names; Healthparse curated labeler →
ticker map (
data/reference/ndc-labeler-tickers.json, 83 companies, 60 listed). - Refresh cadence: weekly, the Monday after CMS posts (CMS posts each Wednesday's file within about a week).
- Row count: 2,666,667 NDC-weeks across 88 weeks, 2025-01-01 to 2026-09-02 (2026-09-08 export); about 30,000 NDCs per week. Index: 88 weekly rows. History before 2025 is loaded on the next off-peak run (the 2024 file is staged), which also fills year-over-year for 2025 weeks.
- Coverage: every NDC has a labeler name; 61% of NDCs carry a ticker. The
rest are private manufacturers (Camber/Hetero, Apotex, Rising, Chartwell,
Padagis, Lannett, Macleods and similar), which carry
companybut a nullticker. - Vintage: derived at export from the latest week loaded.
Table: nadac_weekly_prices
Snowflake: HEALTHPARSE_DATA.NADAC_DRUG_PRICES.NADAC_WEEKLY_PRICES
| Column | Type | Description | Notes |
|---|---|---|---|
ndc |
VARCHAR | 11-digit National Drug Code (5-4-2, zero-padded). | Key with week_date. |
week_date |
DATE | Date of the weekly NADAC file (its "as of" date). | The time axis. Wednesdays. |
effective_date |
DATE | When the current price took effect. | Moves only on a reprice. |
ndc_description |
VARCHAR | Drug description as published: name, strength, form. | e.g. ATORVASTATIN 40 MG TABLET. |
ingredient |
VARCHAR | Best-effort molecule or brand: the description up to the first token containing a digit. | Heuristic; misses names like VITAMIN D3; brands yield the brand name. |
classification |
VARCHAR | G generic, B brand, B-ANDA brand marketed under a generic approval, B-BIO biologic. |
Filter to G for generic deflation. |
otc_indicator |
VARCHAR | Y over the counter, N prescription. |
— |
pricing_unit |
VARCHAR | EA, ML or GM. |
Prices are per unit. |
pharmacy_type |
VARCHAR | C/I chain and independent. |
— |
labeler_code |
VARCHAR | First NDC segment, 5 digits. | Joins to the FDA directory. |
labeler_name |
VARCHAR | Labeler of record from the FDA NDC Directory. | 100% populated. |
ticker / exchange / company |
VARCHAR | Listed parent of the labeler where one exists, from the curated map. | Labeler of record, so a distributor private label (e.g. McKesson's) maps to the distributor. |
nadac_per_unit |
NUMERIC | The price this week, dollars per unit. | — |
prior_week_date / prior_week_nadac_per_unit |
DATE / NUMERIC | The previous weekly file and its price for this NDC. | Prior week must be within 14 days. |
wow_change_pct |
NUMERIC | Week-over-week change, percent. | Zero in most non-reprice weeks. |
price_changed_this_week |
BOOLEAN | True when the price differs from the prior week. | Reprice flag. |
week_52w_ago / nadac_52w_ago |
DATE / NUMERIC | The file 364 days earlier and its price. | Falls back to 357 or 371 days. |
yoy_change_pct |
NUMERIC | Year-over-year change, percent. | Null for 2025 weeks until 2024 loads. |
corresponding_generic_drug_nadac_per_unit |
NUMERIC | For a brand, the NADAC of its generic equivalent. | Brand-to-generic spread. |
_dataset / _vintage / _exported_at |
VARCHAR | See README. | — |
Table: nadac_generic_index_weekly
Snowflake: HEALTHPARSE_DATA.NADAC_DRUG_PRICES.NADAC_GENERIC_INDEX_WEEKLY
One row per week across all generic (G) NDCs.
| Column | Type | Description |
|---|---|---|
week_date |
DATE | Weekly file date. |
n_ndcs / n_ndcs_with_prior / n_ndcs_with_yoy |
INTEGER | Generic NDCs in the file, and how many have a prior-week or 52-week comparison. |
median_wow_change_pct / mean_wow_change_pct |
NUMERIC | Equal-weighted week-over-week change across generic NDCs. |
share_falling / share_rising / share_unchanged |
NUMERIC | Share of generic NDCs whose price fell, rose or held versus the prior week. |
n_repriced |
INTEGER | Generic NDCs whose price changed this week. About 27,000 on a reprice week, dozens otherwise. |
median_yoy_change_pct / mean_yoy_change_pct |
NUMERIC | Year-over-year change across generic NDCs. The cleanest deflation read. |
index_level_median_chain |
NUMERIC | Chained index of the median week-over-week change, base 100 at 2025-01-01. |
Example queries (Snowflake)
-- 1. Generic deflation by listed manufacturer: median YoY price change of
-- each ticker's generic NDCs in the latest week.
SELECT "ticker", "company", count(*) AS ndcs,
median("yoy_change_pct") AS median_yoy_pct
FROM HEALTHPARSE_DATA.NADAC_DRUG_PRICES.NADAC_WEEKLY_PRICES
WHERE "week_date" = (SELECT max("week_date") FROM HEALTHPARSE_DATA.NADAC_DRUG_PRICES.NADAC_WEEKLY_PRICES)
AND "classification" = 'G' AND "ticker" IS NOT NULL AND "yoy_change_pct" IS NOT NULL
GROUP BY 1, 2 HAVING count(*) >= 50 ORDER BY median_yoy_pct;
-- 2. One molecule's weekly price across labelers.
SELECT "week_date", "labeler_name", "ticker", "nadac_per_unit", "price_changed_this_week"
FROM HEALTHPARSE_DATA.NADAC_DRUG_PRICES.NADAC_WEEKLY_PRICES
WHERE "ndc_description" = 'ATORVASTATIN 40 MG TABLET'
ORDER BY "week_date" DESC, "labeler_name";
-- 3. The deflation index: reprice weeks only.
SELECT "week_date", "n_repriced", "share_falling", "median_yoy_change_pct", "index_level_median_chain"
FROM HEALTHPARSE_DATA.NADAC_DRUG_PRICES.NADAC_GENERIC_INDEX_WEEKLY
WHERE "n_repriced" > 1000 ORDER BY "week_date";
Known limits
- NADAC is a retail pharmacy acquisition price, not a manufacturer net price. It excludes rebates and specialty and mail channels, and it is a survey average, not a transaction record.
- Repricing is roughly monthly. Weekly changes are zero for most NDCs in most weeks; use year-over-year or reprice-week measures.
- Ticker is by labeler of record. A drug sold under a distributor's or repackager's label maps to that company, not to the manufacturer.
- The ingredient column is a heuristic on the description text, not a reference to an ingredient database.
- History starts 2025-01-01 in this export; 2024 loads next, which also fills year-over-year for 2025 weeks.