Free API key, instantly: 1,000 calls a day. Get a free key, or use it with no key at 100 a day.
HLA-Verify

Guides › LIMS and data hygiene

How to store HLA typing in a database without losing information

Updated 2026-10-30 · allele examples checked against IPD-IMGT/HLA 3.66.0 on 2026-10-30

To store HLA typing without losing information, keep four things for every result: the string exactly as reported, the IPD-IMGT/HLA release it refers to, the full ambiguity the laboratory reported, and, separately, any normalised form you derive from it together with the release you derived it against. Never let a derived value overwrite the reported one.

HLA names are not stable identifiers. They gain fields, change suffixes and are occasionally deleted, and the sets behind group names are recalculated every quarter. A schema that treats an allele name like a product code will be wrong within a year.

What to keep, and why

KeepExampleWhy
The reported stringA*0101, Cw*0702, A*02:01:01GIt is the primary record; every other value is an interpretation
The release the report used3.40.0, or the report date if unknownNames and groups mean different things in different releases
The full ambiguityA GL String such as HLA-A*02:01:01:01/HLA-A*02:01:01:02LCollapsing a list to one name invents precision
Method or region examinedNGS; SBT exons 2-3A name does not record what was actually sequenced
Normalised name, with its releaseA*01:01 in 3.66.0Derived, re-computable, and dated
Flags from normalisationdeprecated_name, null_alleleSo the next reader sees what was changed and why

The GL String paper by Milius and colleagues makes the release point explicitly: the IMGT/HLA release is not part of a GL String, and whoever creates the string must convey the release separately. Store it in its own column.

A schema that keeps them apart

A minimal two-table design, tested in SQLite: one row per reported value, and one row per normalisation of that value against a given release.

CREATE TABLE hla_typing (
    typing_id        INTEGER PRIMARY KEY,
    sample_ref       TEXT NOT NULL,      -- your internal key; identifiers live elsewhere
    locus            TEXT NOT NULL,      -- 'A', 'B', 'C', 'DRB1', 'DQB1', 'DPB1', ...
    reported         TEXT NOT NULL,      -- exactly as the lab reported it
    gl_string        TEXT,               -- full ambiguity, if the lab supplied it
    reported_release TEXT,               -- IPD-IMGT/HLA release the lab used, if known
    method           TEXT,               -- e.g. 'NGS', 'SBT exons 2-3', 'SSO'
    reported_at      TEXT NOT NULL       -- date of the report
);

CREATE TABLE hla_typing_normalised (
    typing_id        INTEGER NOT NULL REFERENCES hla_typing(typing_id),
    checked_release  TEXT NOT NULL,      -- release this row was computed against
    current_name     TEXT,               -- NULL when unresolvable
    two_field        TEXT,               -- keeps an expression suffix, e.g. A*24:09N
    status           TEXT NOT NULL,      -- valid, renamed, deleted, group, unresolvable ...
    flags            TEXT,               -- e.g. deprecated_name, null_allele
    checked_at       TEXT NOT NULL,
    PRIMARY KEY (typing_id, checked_release)
);

The key on (typing_id, checked_release) means each new release adds rows rather than replacing them, so you can always answer "what did we think this name meant in 3.65.0?". Keep patient identifiers out of both tables and join through your own sample key.

Store names as text, never as numbers or fixed widths

Several storage shortcuts look harmless and corrupt real names:

  • Fixed-width fields. Fields are not two digits. In IPD-IMGT/HLA release 3.66.0, C*07:1245:01:01 has a four-digit second field and DPB1*1537:01:01 a four-digit first field. A column sized for A*02:01:01:01 will truncate them.
  • Numbers. Storing fields as integers drops leading zeros, and 02 and 2 are not interchangeable in a name.
  • Splitting off the suffix. A*24:09N is a null allele; the N is part of the name. A schema that stores fields in numeric columns and drops trailing letters turns it into a name that does not exist. Keep the suffix in the same string, and keep the whole name as text.
  • Assuming a field count. Names have one to four fields depending on the allele. A*03:06 is a complete assigned allele with two.

If you need the fields for queries, derive them in a view or a generated column from the stored text, not the other way round.

Keep ambiguity as ambiguity

A typing result is often a list or a group, not one allele. Three rules:

  1. Do not keep only the first name of a list. Order inside a GL String carries no meaning, according to its specification.
  2. Keep genotype alternatives as whole pairs. A GL String with | lists alternative genotypes; splitting it into per-allele lists allows combinations the typing ruled out. The ambiguity guide has an example.
  3. Store G and P codes with their release. A G group is a set defined by the release files. In release 3.66.0, A*02:01:01G has 554 members, including null alleles such as A*02:43N. The same code in another release may have a different membership.

The GL String guide covers the format, which is designed to carry all of this in one text column.

Plan for names to change

Every quarterly release can change stored names. In 3.66.0, for example, A*01:284 became A*01:284:01 because a second allele was named, and A*02:01:14Q lost its suffix. The IPD-IMGT/HLA history file keys every allele on a permanent HLA ID, which does not change when the name does.

A workable policy:

  • Re-normalise stored names against each new release, adding rows rather than overwriting.
  • Record the HLA ID where you can resolve one, so a name can be traced through later renames.
  • Separate renamed, deleted and never-assigned names; they need different handling. The releases guide explains each.
  • Keep the release in every export, so downstream users do not have to guess.

Validate on the way in

Problems are cheapest to catch at import: legacy spellings, deleted names, and reporting codes passed through as if they were alleles. The import validation guide lists the checks. At minimum, check every new value against the allele list for a named release before it is stored, and flag rather than silently fix anything that needed conversion.

POST /v1/normalize takes a batch of reported strings and returns, for each, the current name, the two-field form, the G group and flags such as deprecated_name, with the release named in the response, which maps directly onto the normalised table above. Send allele names only, never patient identifiers.

Frequently asked questions

What is the most important thing to store with an HLA typing?

The string exactly as reported, together with the IPD-IMGT/HLA release it refers to. Everything else can be re-derived from those two; neither can be recovered once lost.

Should I overwrite old HLA names with current ones?

No. Store the current name alongside the reported one, with the release used to derive it, so the conversion can be audited and repeated when names change again.

How should HLA allele names be stored in a database column?

As text, whole, including any expression suffix. Do not use fixed widths or numeric fields, because field lengths vary and suffixes such as N are part of the name.

How do I store an ambiguous HLA typing?

Keep the full GL String the laboratory reported, or the full allele list, together with the release. Do not reduce it to its first name or split genotype alternatives into independent lists.

Sources

HLA-Verify is a research-and-evaluation tool for nomenclature and reference-release validation. It is not a medical device and this guide is not clinical advice. Send allele names, never patient identifiers.