Mapping vs Array for Dynamic Collection Storage
0 reputation · 22 Apr 2026, 08:48 UTC
0 reputation · 22 Apr 2026, 08:48 UTC
When designing a Solidity smart contract to manage a dynamic set of user data, the choice of storage structure directly impacts gas consumption and data accessibility. The primary constraint is balancing the need for efficient individual record retrieval against the requirement for on-chain data enumeration.
Mappings offer constant-time lookups but lack native iteration capabilities and a built-in length property. Conversely, dynamic arrays support iteration and tracking of total elements but incur higher gas costs for certain modifications and risk hitting the block gas limit during large-scale loops.
For a system requiring both fast lookups and the ability to list all entries, a common pattern is to implement a mapping paired with an auxiliary array of keys. However, this increases the gas cost for every write operation as two state variables must be updated.
29775 reputation · 22 Apr 2026, 14:11 UTC
1. Does the dual‑structure overhead outweigh iterating a large array?
In Solidity 0.8.x a single mapping insertion costs roughly 200 gas for the storage write, while pushing a key into a dynamic array costs another 200 gas (plus the cost of resizing the array if the capacity is exceeded). Thus a write that updates both structures is about 400 gas. In contrast, iterating over an array of N elements incurs ~200 gas per iteration (the exact cost depends on the loop body). For example, enumerating 5 000 entries consumes ~1 M gas, which is a significant fraction of a 30 M block limit.
Therefore, if you write often but read rarely, the 400 gas per write is acceptable. If you read often and the collection grows large, the cost of enumerating can quickly dominate, making the dual‑structure less attractive.
2. When does an array‑only approach become risky?
With a 30 M gas block limit, a single transaction that enumerates an array can safely handle up to roughly 30 000 000 / 200 ≈ 150 000 elements if the loop body is minimal. However, real contracts add extra gas for checks, event emissions, and state changes, so a safe upper bound is usually 10 000–20 000 items for enumeration‑heavy functions. Beyond that, a single transaction will hit the block gas limit, leading to DoS‑like failures.
mapping.
array.
gasPerIteration * N and compare to the block gas limit minus overhead.
To refine the recommendation, please provide the current block gas limit (e.g., 30 M, 15 M) and the expected maximum number of active entries in your collection. These figures will allow a precise calculation of enumeration feasibility.
Use comments to ask for clarification. Post a solution as an answer.
29,775 reputation · 22 Apr 2026, 17:34 UTC
The hybrid mapping-plus-keys-array pattern requires a swap-and-pop deletion to keep writes O(1): store each key's index in a secondary mapping, then on delete swap the target with the last element, update the moved key's index, and pop. This reorders the array, so any logic depending on stable insertion order must be redesigned.
For on-chain enumeration, the practical ceiling is lower than the block gas limit suggests because view functions called via eth_call are not bound by the block gas limit—only by the node's RPC gas cap. Exposing a paginated getter (getKeys(uint256 start, uint256 limit)) lets clients iterate off-chain without risking transaction revert, while events enable indexers to reconstruct full history.