Skip to main content
Transaction IDs in Formance Ledger are automatically assigned by PostgreSQL sequences. Understanding how these sequences behave is important when working with the ledger, especially when you notice gaps or “holes” in the transaction ID numbering.

Expected Behavior: Sequence Gaps

It is normal and expected to see gaps in transaction ID sequences. For example, you might observe transaction IDs jumping from 17498 directly to 17531, skipping several numbers in between. This is not a bug - it’s an intentional design choice in PostgreSQL for performance reasons.

Why Do Gaps Occur?

Transaction ID sequences can have gaps for several reasons:

1. Rolled Back Transactions

When a SQL transaction is rolled back, any sequence values that were consumed during that transaction are not returned to the sequence. This is because PostgreSQL sequences operate outside of the transactional context.

Why Sequences Are Non-Transactional

Sequences are designed to be non-transactional to avoid concurrent locking contention. Rolling back a nextval() operation would require coordination between all transactions using that sequence, which would severely impact performance.

2. Failed Database Connections

If a database connection fails during a transaction, the sequence values consumed up to that point are lost and will create gaps in the sequence.

3. Dry-Run Operations

When you use the dry-run parameter to preview transactions without committing them, the operation still consumes sequence values from the transaction ID sequence. Since these transactions are never committed to the ledger, the consumed IDs become gaps.
When using the dry-run feature extensively in production environments, be aware that it will contribute to gaps in your transaction ID sequence. This is normal behavior and does not affect the integrity of your ledger.

4. Database Crashes and Recovery

PostgreSQL sequences pre-allocate values in batches for performance. During crash recovery, any pre-allocated but unused values are lost, creating gaps in the sequence.

Impact on Your Application

These gaps have no negative impact on ledger functionality:
  • ✅ All committed transactions are recorded correctly
  • ✅ Transaction ordering is preserved
  • ✅ Data integrity is maintained
  • ✅ Audit trails remain complete
The only effect is that transaction IDs are not consecutive numbers - they remain unique and increasing, which is what matters for database operations.

When to Be Concerned

You should only investigate further if you notice:
  • Extremely large gaps (thousands of missing IDs in a short time period) - this might indicate connection issues or excessive dry-run usage
  • Decreasing transaction IDs - this would indicate a serious problem and should never happen
  • Duplicate transaction IDs - this would indicate a critical database issue

Best Practices

Don't Rely on Consecutive IDs

Never build application logic that depends on transaction IDs being consecutive. Use transaction IDs only for:
  • Uniquely identifying transactions
  • Ordering transactions chronologically
  • Creating pagination cursors

Use Timestamps for Business Logic

If your business logic requires tracking continuous sequences (like invoice numbers), implement a separate gapless sequence using application-level logic rather than relying on database sequence IDs.