Deep Dive June 10, 2026 · 6 min read

Why Invoice Numbers Must Be Gap-Free — and How We Guarantee It

A missing invoice number isn't a cosmetic bug — to a tax auditor it's a question you have to answer. Here's why the sequence matters and what it takes to keep it intact.

In most of the world, including under Indian GST, a business's tax invoices must be numbered in a consecutive series with no gaps. The reason is simple: a gap looks like a deleted invoice. If you issued numbers 1001, 1002, and 1004, an auditor's first question is "where is 1003, and what are you hiding?" Even if the answer is innocent — a software glitch, a cancelled order — you now have to prove a negative. Gap-free numbering exists so the sequence itself is evidence that nothing was quietly removed.

Why the obvious approach fails

The naive implementation is SELECT MAX(number) + 1, or a database auto-increment column. Both break in ways that matter:

  • Concurrency. Two invoices created at the same moment both read the same max and both claim the next number — a collision. Add a unique constraint and one of them now crashes instead.
  • Rollback gaps. Database auto-increment sequences deliberately do not reuse a number when a transaction rolls back. That's correct for surrogate keys and catastrophic for tax invoices — every failed insert burns a number and punches a permanent hole in your series.
  • Deletion. If "cancelling" an invoice deletes the row, its number vanishes from the sequence. Now you have a gap with no record of why.

How DocForge does it

DocForge allocates each invoice number under a file lock. Acquiring the lock serialises allocation: only one invoice can be claiming a number at any instant, so collisions are impossible and the next number is always exactly one more than the last committed one. The allocation and the invoice record commit together — if the render fails, the number isn't consumed, so failures don't create gaps either.

The second half is the void rule. You can't delete an invoice in DocForge; you void it. A voided invoice keeps its number, clearly marked void, and stays in the series. The number is never reissued to a different invoice. So the sequence is always complete and always explains itself: every number is present, and the void ones say exactly why they're void.

What you get from it

The payoff is an invoice register you can hand to an accountant or an auditor without a covering explanation. Run down the numbers — 1001, 1002, 1003 (void), 1004 — and the story is self-evident. No gaps to justify, no collisions to reconcile, no spreadsheet of "numbers we skipped and why." The compliance property is built into how the number is allocated, not bolted on afterward.

Numbering sounds like the most boring part of an invoice. It's also the part most likely to turn an audit into a bad week — which is exactly why it's worth getting mechanically right.