Riwayat

The Qur’an reaches us through several transmitted readings. They are all the same text, and they are not the same data. This page is about the second half of that sentence: what actually changes in the files when a user picks a different reading, so you can decide what to cache, what to key, and what to re-resolve.

Time
About 10 minutes

The two-level hierarchy matters only because our identifiers sit on the lower level. hafs, warsh, qalun, duri, susi, shubah and bazzi are transmitters' names, and each one is a selector for a complete printed text.

The seven we ship

KeyRiwayahCounting systemAyat in this muṣḥafSystem total
hafsḤafṣ ʿan ʿĀṣimKufi6,2366,236
shubahShuʿbah ʿan ʿĀṣimKufi6,2366,236
warshWarsh ʿan NāfiʿLast Madani6,2146,214
qalunQālūn ʿan NāfiʿLast Madani6,2146,214
durial-Dūrī ʿan Abī ʿAmrFirst Madani6,2176,214differs
susial-Sūsī ʿan Abī ʿAmrFirst Madani6,2186,214differs
bazzial-Bazzī ʿan Ibn KathīrBetaMakki6,2206,219differs

Muṣḥaf counts come from quran-text’s own files; system totals from qiraat-ayah-map. Both are read at build time. Where they differ, both numbers are correct about different questions — see below.

Two of the transmitters share a reciter in three places — Ḥafṣ and Shuʿbah both transmit ʿĀṣim, Warsh and Qālūn both transmit Nāfiʿ, al-Dūrī and al-Sūsī both transmit Abū ʿAmr — and that pairing does not make their data interchangeable. At 6:124 the Ḥafṣ text reads رِسَالَتَهُۥ where Shuʿbah reads رِسَٰلَٰتِهِۦ; al-Dūrī and al-Sūsī differ in their printed ayah count. Sharing a reciter tells you nothing you can use in code.

What changes when the riwayah changes

RiwayahWords printedAyat printedBasmalah numberedAyat in surah 36First word of 1:1
Ḥafṣ
hafs
77,4326,236yes83بِسۡمِ
Shuʿbah
shubah
77,4326,236yes83بِسۡمِ
Warsh
warsh
77,4316,214no82ࡴ۬لْحَمْدُ
Qālūn
qalun
77,4316,214no82ࡴ۬لْحَمْدُ
Dūrī
duri
77,4316,217no82اِ۬لۡحَمۡدُ
Sūsī
susi
77,4316,218no82ࡵ۬لۡحَمۡدُ
Bazzī
bazzi
77,4326,220yes82بِسۡمِ

Read at build time from public/demo/fatiha.json and public/demo/lookup.json, which scripts/sync-demo-data.mjs built from each muṣḥaf file in quran-text at the commit pinned in public/demo/SOURCES.json. The last column is the first word of what each edition numbers ayah 1 of surah 1: where the basmalah is not numbered, ayah 1 begins after it.

Read that table left to right and you have the list of things a riwayah switch invalidates:

Changes with the riwayahEvidence in the tableConsequence
The number of words77,432 against 77,431any array index into words belongs to one edition
The number of ayatfive different totals across seven editionsany for (a = 1; a <= N; a++) belongs to one edition
Whether the basmalah is ayah 1yes for three, no for four1:1 is not the same words in every reading
Where ayat end inside a surahsurah 36 has 83 ayat in Ḥafṣ and 82 in the othersḤafṣ numbers the opening letters alone as 36:1; Warsh does not, so 36:2 is already a different verse — see ayah counting
The counting systemfour systems across seven editionstranslate references, never add an offset

The letters change

The same word, at the same position, in all seven:

RiwayahAs printedCode points
Ḥafṣ
hafs
مَٰلِكِU+0645 U+064E U+0670 U+0644 U+0650 U+0643 U+0650
Shuʿbah
shubah
مَٰلِكِU+0645 U+064E U+0670 U+0644 U+0650 U+0643 U+0650
Warsh
warsh
مَلِكِU+0645 U+064E U+0644 U+0650 U+0643 U+0650
Qālūn
qalun
مَلِكِU+0645 U+064E U+0644 U+0650 U+0643 U+0650
Dūrī
duri
مَلِكِU+0645 U+064E U+0644 U+0650 U+0643 U+0650
Sūsī
susi
مَّلِكِU+0645 U+064E U+0651 U+0644 U+0650 U+0643 U+0650
Bazzī
bazzi
مَلِكِU+0645 U+064E U+0644 U+0650 U+0643 U+0650

Word position 10 of surah 1 in each edition’s own words array, from public/demo/fatiha.json. It is the same word in every reading — the first word of the ayah Ḥafṣ numbers 1:4 — and the same shared word number in Quran Text.

Three visibly different spellings. And where two editions do look the same, the code points still need not match: the first word of the basmalah is بِسۡمِ in the Ḥafṣ text, with its sukūn as U+06E1, and بِسْمِ in Warsh, with U+0652. So even "the same word looks the same" does not give you string equality across editions. The only thing that survives is the shared word number — see Word identity.

Across the whole text, this is how often the seven disagree at the level of letters, spelling of the ā, word division or presence:

statusWordsWhat it means
alif_variant198one skeleton once every ā is spelled out — the ā is on the line in one hand and above it in another
rasm_variant60the editions disagree about the letters on the line
word_boundary16a source prints the word joined to its neighbour, or a muṣḥaf really writes it joined
partial3the word is absent from at least one edition
Total277words where at least one edition differs at this level

Read at build time from public/demo/differences.json, the demo’s copy of data/differences.json in quran-text. The descriptions paraphrase the status vocabulary in that repository’s docs/files.md; the file itself carries only the key.

The vowelling differs far more often than that — the differences file leaves out words that differ only in their marks — so treat these counts as a floor, not as "277 places where the readings differ".

A riwayah is not a display setting

It is tempting to model the reading as a toggle beside dark mode: keep one text in memory and switch the font. Nothing throws when you do this. A cache keyed on 2:255, a search index built over one edition, or an annotation offset computed against one text is served to a reader of another. Choose the riwayah when you load, put its key in every cache key, and re-resolve every stored reference through the mapping when it changes — a riwayah is an entity, not a column on one (Engineering, rule 1.2).

The font changes

Each edition is typeset in its own publisher font, and it is not decorative. Quran Text names the family in every muṣḥaf file — KFGQPC HAFS Uthmanic Script, KFGQPC Warsh Uthmanic Script and so on — and the demo on this site loads seven woff2 files, one per edition, because three of the editions use code points almost no general font draws. The Quran Text reference has the details; the short version is that "the text renders as boxes" is a font problem, not missing data.

Which blocks cover which riwayat

Coverage is uneven: splitting a muṣḥaf into words is hard, and annotating tajwīd is scholarly work per reading. Read this before promising a feature in every reading.

BlockRiwayat coveredWhere it says so
Quran Textall sevendata/catalog.json
Qiraat Ayah Mapall — it maps counting systems, not textsrawis/
Quran SVGḤafṣ, Warsh, Qālūn, al-Dūrī, Shuʿbahthe mushafs/ folders
Quran SVG ElementsḤafṣ only (hafs-kfgqpc)VERSION.json
Quran Enginethe split muṣḥafs — Ḥafṣ todaythe release's page data
Quran TajweedḤafṣ only; another riwayah is an error, not a settingriwayah: "hafs-an-asim" in the annotations
Quran Assetsornaments for eight printed muṣḥafsthe index's mushafs[].key

So a reader of Warsh can have text, page artwork and reference translation, but not word-level tapping and not tajwīd colouring. Design the feature matrix from this table, not from the Ḥafṣ experience.

What to do

  1. Make the riwayah part of every key

    Cache entries, bookmarks, search indexes, audio timings: all of them are per edition.

    type Riwayah = "hafs" | "shubah" | "warsh" | "qalun" | "duri" | "susi" | "bazzi";
    
    // wrong — collides the moment a second reading is loaded
    cache.set(`ayah:${surah}:${ayah}`, text);
    
    // right
    cache.set(`ayah:${riwayah}:${surah}:${ayah}`, text);
    
  2. Read counts from the loaded edition

    Every muṣḥaf file carries its own counting.ayah_count and mushaf.word_count. Use them; never a literal.

  3. Join across editions on the word number, not on text

    Quran Text gives every word one integer shared by all seven editions. That is the only safe way to say "this word" in more than one reading at once.

  4. Translate references when the reading changes

    A stored 36:2 in Ḥafṣ is a different verse in Warsh. Use the mapping rather than arithmetic; the offset is not constant within a surah. Map ayah references between counts is the guide.

Try it live

The same ayah in all seven editions, from the real dataset, with each edition’s own spelling and boundaries.

How this data is made

Each of the seven editions in Quran Text is extracted unedited from a digital package published by the King Fahd Glorious Qurʾān Printing Complex, the Madinah muṣḥaf in that reading, and the file names the package and its SHA-256. The cross-edition comparison, the shared word numbering and the measurement of which counting system each edition follows are derived by the build. The seven are a complete comparison of the material the publisher provides, not of the ten canonical qirāʾāt: three reciters have no published edition here.