Ayah-counting systems

This is the single most common source of silent bugs in Qur’an software. It costs nothing to get right at the start and is expensive to retrofit, because by then the wrong numbers are in your database.

Time
About 8 minutes

The part that surprises most developers: the text does not change. Not a letter. Two scholars reading the identical text disagree only about where to put the numbered break between one verse and the next. So a "different count" is not different content — it is different punctuation of the same content.

That is why the bug is silent: the text renders correctly and the references point somewhere else.

Sūrat al-Ikhlāṣ makes it concrete. It is four ayat in First Madinan, Last Madinan, Basran and Kufan, and five in Makkan and Damascene. The entire question is whether lam yalid wa-lam yūlad is one ayah or two. Nothing is added and nothing is removed; a break moves.

Numbering only — never wording

A counting system is not a reading. Choosing a different one changes where the numbers fall and nothing else: not a letter of the text, and none of the rules of recitation. The qirāʾāt do differ in wording — 1:4 is مالك يوم الدين in Ḥafṣ and ملك يوم الدين in Qālūn — but that is a different subject, and Qiraat Ayah Map does not carry it. See Riwayat.

The six systems

SystemArabicTotal ayatAssociated qurrāʾ
First Madinan
madani-first
المدني الأول6,214abu-jafar
Last Madinan
madani-last
المدني الأخير6,214nafi
Makkan
makki
المكي6,219ibn-kathir
Basran
basri
البصري6,204abu-amr, yaqub
Damascene
dimashqi
الدمشقي6,226ibn-amir
Kufanreference
kufi
الكوفي6,236asim, hamza, kisai, khalaf

Read at build time from public/demo/qiraat.json, which scripts/sync-demo-data.mjs built from the Qiraat Ayah Map repository at a pinned commit.

Two things in that table catch people out.

First and Last Madinan share a total of 6,214 — and they are still different systems. They place some of their boundaries in different places, and those differences cancel out in the sum. So you cannot identify a counting system by its total, and comparing totals is not a valid equality check.

6,236 is not a constant

It is the Kufan total. Ḥafṣ follows the Kufan tradition, and Ḥafṣ is what most of the world prints, so the number looks universal. Write for (let a = 1; a <= 6236; a++) and your app is correct until the first user switches riwayah, then it truncates or overruns without an error.

The second trap: a total is not a muṣḥaf's ayah count

These two numbers sound like the same thing and are not:

They can disagree. The KFGQPC al-Sūsī muṣḥaf we ship prints 6,218 ayat, while the Basran system its qāriʾ is associated with totals 6,204. Both numbers are correct about different questions.

Careful

Our own repositories currently answer this differently, and we have not resolved it. quran-text measures the printed al-Sūsī edition closest to First Madinan; qiraat-ayah-map assigns Abū ʿAmr to Basran. If you join the two datasets you will hit the contradiction. It is recorded in our cross-repo notes and needs a scholar, not a patch.

What to do instead

  1. Never write a count as a literal

    Read it from the riwayah you loaded, because numbering systems differ (Quranic text, rule 5.2). Every dataset we publish carries its own totals, so the correct number is always already in memory.

    // wrong — correct only for Ḥafṣ
    for (let a = 1; a <= 6236; a++) { /* ... */ }
    
    // right — correct for whatever the user selected
    for (let a = 1; a <= mushaf.ayahCount; a++) { /* ... */ }
    
  2. Store the system alongside every reference you persist

    A bookmark saved as 7:206 is not enough information to restore. Saved as { surah: 7, ayah: 206, counting: "kufi" } it can be translated into whatever the user is reading later — the ayah key is surah and ayah together (Engineering, rule 2.1).

    type StoredRef = { surah: number; ayah: number; counting: CountingSystem };
    
  3. Translate references with Qiraat Ayah Map, not with arithmetic

    The offset between two systems is not constant across a surah: boundaries move independently, so there is no delta to add. Use the mapping, and name the riwayah and the numbering system explicitly (Engineering, rule 3.2) on both sides of it.

Try it live

Pick a reference and watch the same ayah resolve to different numbers across all six systems, from the real dataset.

Where the six come from

They are not conventions someone chose. Each is a transmission with a named chain, and there are six because the muṣḥafs ʿUthmān sent to the garrison cities were six. Which chain stands behind each system, which reciters rely on it, and how well attested each individual boundary is are all set out in method and evidence.

How this data is made

Qiraat Ayah Map does not store six full copies of the Qur’an. It stores the boundary primitives, the places where the traditions agree and disagree about a break, and each system's numbering is derived from those. Rebuilding all six from the primitives reproduces every published total exactly, and the derived numbering ships with the package.