At the Bennett Institute we get asked if we have a way of converting BNF codes (which are used in the NHS Business Services Authority (NHSBSA) data that we use to power to dm+d codes.

The tables that allow us to do this are in our back-end SQL server. Although we haven’t previously attempted to make them available to users, we thought we would take the opportunity to see if a) they are fit for purpose, and b) could be shared openly.

We are aware that NHSBSA do provide a BNF code to dm+d map, but one of our users had specifically asked whether we could also provide a map from BNF codes to Virtual Therapeutic Moieties (VTM), which the NHSBSA doesn’t currently include.

We have created a map in the form of a CSV file, which is available to freely download here. Please read on for more information on how the map was developed, and caveats in its use.


We have written in detail about the structures of the BNF code, dm+d, and how they differ from each other. Below is a brief summary.

BNF coding

BNF code: a hierarchical 15 digit code, based on the legacy version of the British National Formulary (BNF) hierarchy.


Virtual Therapeutic Moiety (abstract) — VTM

VTM is the highest level within dm+d. It is an abstract representation of a medicine or device. It is just the chemical name without any mention of the strength or formulation. Example: Amoxicillin

Virtual Medicinal Product (abstract) — VMP

VMP describes the abstract or generic medicinal product. Example: amoxicillin 250mg capsules

Actual Medicinal Product (real product) — AMP

AMP provides a unique description of a medicine or device that has been made available by a manufacturer or supplier but does not describe the pack size or the quantity of the medicine or device. Example: Amoxicillin 250mg capsules — Actavis UK Ltd

Although there are more granular levels of dm+d (virtual and actual medicinal product packs, VMPP/AMPP), BNF codes do not have this level of detail, and map to AMP/VMP level.

Creating the map

We created the BNF code to dm+d map using a Jupyter Notebook. You can find the full notebook on our GitHub page, but below is a brief description of what we did, and what we found out.

We created a map of BNF code to VMP/AMP and VTM using existing tables on our BigQuery server, which we obtain weekly from the NHS TRUD service, and then tested this using 12 months of prescribing data (September 2022 - August 2023, the most recent available) to check whether there were any issues for unmapped prescribed medicines.

dmd type (AMP/VMP)AMP/VMP codedm+d nameVTM codeVTM nameBNF CodePrevious VMP codePrevious VMP date
vmp6259002Hydrogen peroxide 3% solution31231007Hydrogen peroxide1311060I0AAABAB422491100000000015/08/2005
vmp68461003Lubricant gelsNaNNaNNaN348531100000000004/01/2006
vmp134460003Irbesartan 300mg / Hydrochlorothiazide 12.5mg tablets398914000Irbesartan + Hydrochlorothiazide0205052A0AAABABNaNNaN
vmp134461004Irbesartan 150mg / Hydrochlorothiazide 12.5mg tablets398914000Irbesartan + Hydrochlorothiazide0205052A0AAAAAANaNNaN
vmp134463001Telmisartan 20mg tablets129487008Telmisartan0205052Q0AAACACNaNNaN

Figure 1: sample output from BNF code to VMP/AMP and VTM map

Products with either a missing AMP or VMP code

We filtered the results to find any prescribed products that didn’t have a corresponding VMP or AMP code:

dmd type (AMP/VMP)AMP/VMP codedm+d nameVTM codeVTM nameBNF CodePrevious VMP codePrevious VMP dateBNF namePrescription Items (Sep 22 - Aug 23)
NaNNaNNaNNaNNaN190201000AABLBLNaNNaTException Handler Unspecified Item314805
NaNNaNNaNNaNNaN190201000AABPBPNaNNaTException Handler High Volume Unspecified Item184530
NaNNaNNaNNaNNaN190201000AABNBNNaNNaTException Handler Discount Not Deducted Item20008
NaNNaNNaNNaNNaN0913261J0BCAAABNaNNaTProZero liquid4549
NaNNaNNaNNaNNaN090402000BDFHA0NaNNaTFresubin Energy tube feed liquid unflavoured205

Figure 2: Top 5 prescribed products with no mapped AMP/VMP code

We can see from the above there are very few items apart from “unspecified items”, which by definition cannot have a BNF code. Therefore we can be confident that the vast majority of items prescribed in primary care have a corresponding AMP or VMP code.

Product mapping to VTM

We next checked to see whether there were any prescribed products which didn’t map to an appropriate VTM code.

BNF namePrescription Items (Sep 22 - Aug 23)
Laxido Orange oral powder sachets sugar free2655605
FreeStyle Libre 2 Sensor2150585
Macrogol compound oral powder sachets NPF sugar free1917581
Dermol 500 lotion1821608
Otomize ear spray1404453
Epimax original cream1216588
Vitamin B compound strong tablets1038779
GlucoRx Nexus testing strips1020083
Medi Derma-S barrier cream780871

Figure 3: Top 10 prescribed products with no mapped VTM code

There appeared to be a significant number of items prescribed which did not have a corresponding VTM code.

On further investigation we found that this consisted of three main groups of preparations:

  • Devices (for example Freestyle Libre 2 sensor), for which there is no chemical ingredient, and therefore does not have a VTM
  • Medicine preparations which have more than 3 ingredients listed on dm+d. For example Macrogol compound oral powder sachets NPF sugar free has 5 separate ingredients: Macrogol ‘3350’, Bicarbonate, Potassium, Chloride, and Sodium.
  • Combination products, for example Evorel Sequi patches which have two different patch types in the pack, and Microgynon 30 ED, which has a placebo tablet as well as an active tablet.

None of the products listed above will have a corresponding VTM code.


We are confident that the BNF code to dm+d (including VTM) is accurate and as complete as possible, with the following caveats:

  • It is current as of November 2023
  • No medicines with more than three listed ingredients, in a combination pack, or devices will have a VTM code

We have also included previous VMP codes - this is important as changes to the VMP codes happen quite frequently, and some codelists may contain previous versions.

The BNF to dm+d code map is freely available as a CSV file for anyone to download from here. See below for fields:

typeType of dm+d code (AMP or VMP)
iddm+d code (AMP or VMP)
nmdm+d name
vtmVTM code
vtm_nmVTM name
bnf_codeBNF code
vmp_previousPrevious VMP code
Vmp_previous_dateDate of previous VMP code change