In this track: Storage, memory and layout
Solidity storage slots
See how persistent values fit into 32-byte slots.
Imagine numbered drawers, each with 32 little spaces. Small values can share a drawer if the compiler’s layout rules allow it.
In this simple default-layout example, two uint128 values come before one uint256. Each slot holds thirty-two bytes.
Animated local teaching model. No wallet, RPC or live blockchain data. Some labels and hashes are abbreviated for readability.
Persistent drawers
A contract’s storage persists across calls. In Solidity’s default layout, the first state variable starts at slot zero. A uint256 needs 32 bytes. Smaller adjacent value types can share a slot, packed from the lower-order end, if they fit.
Order changes packing
Two uint128 values fit in one slot. A uint256 followed by a bool requires two slots. The storage visualizer lets you change a simple sequence of value types and inspect slot numbers and byte offsets. It deliberately handles elementary value types only.
Mappings are different
A mapping’s entries do not sit consecutively in its declared slot. For a mapping from an address to a value at slot p, the entry location uses keccak256(abi.encode(key, p)). Other key types have their own encoding rules. Dynamic arrays and nested structures also require layout rules beyond simple packing.
Be careful with upgrades
Changing the order or types of existing state variables in an upgradeable contract can make new code interpret old values incorrectly. Production layouts need compiler output and consideration of inheritance, structs and explicit layout choices. Our diagram teaches packing; it is not an upgrade safety audit.
How many slots do two adjacent uint128 values need in a simple default layout?
Each is 16 bytes, so both fit in a single 32-byte slot.
Original explanations by EtherTools. Examples are educational and source-linked; this site is independent of the Ethereum Foundation. Our approach.