Fractional indexing
A technique for ordering items in a list (or cards on a kanban board) by giving each item a fractional position value, so inserting between two existing items doesn't require renumbering anything else.
Fractional indexing is a technique for keeping a list of items in a chosen order without having to renumber them whenever someone inserts, moves, or reorders an item. It's how modern collaborative tools (Figma, Linear, Notion, GritShip) keep kanban cards and list items consistent across many simultaneous users without conflicts.
The naive approach (and why it breaks)
The obvious way to order tasks is to give each one a position number: 1, 2, 3, 4, 5. To insert a new task between #2 and #3, you have two bad options:
- Renumber everything after the insertion point. Now #3 becomes #4, #4 becomes #5, and so on. Every move requires touching every following row in the database. With multiple users moving cards at the same time, this is a recipe for race conditions.
- Use floats (e.g., position 2.5). This works for a few inserts, but eventually you run out of float precision, especially with many concurrent edits.
Neither approach scales. Real production tools use fractional indexing instead.
How fractional indexing works
Each item gets a string position like "a", "b", "c". To insert between "a" and "b", you generate "aa" (or "a5", or any string that sorts lexicographically between "a" and "b"). To insert between "a" and "aa", you generate "a0", and so on. The string can grow as needed, and you never have to renumber existing items.
Two users dragging cards simultaneously can both insert without conflict — each generates a new fractional key independently, and both inserts succeed.
When you encounter it
You don't think about fractional indexing day-to-day, but the consequence is visible: in tools that use it, dragging a card between two others is instant and never reorders anything you didn't touch. In tools that don't, you sometimes see cards "jump" or "snap back" after a drag — that's a renumber race.
How GritShip handles this
Every task in GritShip stores a fractional position string (column-scoped). Drags update only the dragged card's position. The change is applied optimistically in the client store and synced to the database in the background. Multiple teammates can drag at the same time without conflict because no two cards ever need the same key.
Looking for a tool that respects these concepts?
GritShip is project management for developers who'd rather ship than configure.
Try GritShip free →