Why Trello Cards Don't Need Renumbering: Ordering by Position Between Neighbors
Trello avoids renumbering every card on drag-and-drop by storing order as a numeric position between neighbors. Learn how midpoint insertion works, when precision runs out, and how to observe pos via the REST API.
03 Nov 2025, 18:11 UTC

Dragging a card to the middle of a long list should be cheap. With index-based ordering it is not: inserting at position 3 means incrementing the index of every card after 3. That is an O(n) write per drag, and it gets worse with concurrent editors.
Trello avoids the renumbering tax by storing order as a numeric position between neighbors, not as a fixed index. A card gets a pos value. To insert between two cards you pick a number between their pos values and write only the new card. No other cards move.
The O(n) pain of index-based ordering
Index ordering is intuitive. Card 1, Card 2, Card 3. Move a card to the top and you must rewrite the index for every card that shifts down. In a busy board with drag-and-drop and multiple clients, those writes collide and pile up.
The cost is not just writes. It is coordination. Two users inserting near each other can produce conflicting renumbers that require server-side reconciliation.
Fractional positions: order without renumbering
The pattern Trello has described publicly is fractional positioning. Each card carries a numeric pos that defines its order within a list. Sorting by pos gives the visual order.
Insertion is local. Given neighbors with pos A and pos B where A < B, a new card can be placed with pos = (A + B) / 2. Only the new card is written. The rest of the list is untouched.
The REST API surfaces this concept. Cards expose pos, and create or move operations accept a numeric pos or the keywords top and bottom. That means the ordering model is observable without touching internal code.
Worked midpoint example
This is an illustrative calculation, not measured data from a real board.
- Existing cards: Card X at pos 1000, Card Y at pos 2000.
- Insert Card Z between them: pos = (1000 + 2000) / 2 = 1500.
- Insert Card W between X and Z: pos = (1000 + 1500) / 2 = 1250.
Each insertion halves the gap. After k inserts into the same gap the spacing shrinks proportionally to initialGap / 2^k. The ordering stays correct as long as the numbers remain distinguishable.
Precision runs out and re-spacing recovers
Numeric precision is finite. Halving a gap repeatedly eventually produces a midpoint that cannot be represented distinctly from its neighbors. Two clients inserting into the same narrow gap can also compute the same midpoint, creating a collision.
The escape hatch is re-spacing. Periodically the whole list is rewritten with fresh, evenly distributed positions. That is a rare O(n) repair that buys many cheap O(1) inserts. It also resolves ties and exhausted gaps.
Limitations to keep in mind: re-spacing is a write amplification event, it must be done safely under concurrency, and the exact trigger threshold depends on the numeric type and system policy. The pattern is generic; current Trello internals may have evolved since the original engineering discussion.
How to observe pos in the live REST API
You can inspect the model on a test board you control. This requires a Trello API key and token with read access to the board.
List cards for a list and inspect pos:
GET https://api.trello.com/1/lists/{listId}/cards?key={apiKey}&token={token}&fields=name,posWhere to run: any HTTP client from a machine with network access to api.trello.com. Required permissions: API key + token authorized for the board. Meaningful placeholders: {listId}, {apiKey}, {token}.
Expected checks: pos values increase with visual top-to-bottom order. Creating a card with a pos between two neighbors should place it between them visually.
Risks: write operations such as POST /1/cards or PUT /1/cards/{id} modify board state. Use a disposable board for experiments.
A practical way to verify behavior is to create a free board, add several cards to one list, read their pos values, then create a new card with a pos between two existing cards and re-read the list to confirm relative ordering.
Use fractional positioning when you need cheap, concurrent inserts in a sortable UI list. If your list is append-only or rarely reordered, plain integer appends are simpler and avoid re-spacing logic altogether.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.