πŸ—„οΈ Storage Slots: 32-Byte Data Layout

Learn how Ethereum packs variables into 256-bit storage slots

πŸ“¦ Storage Slots Explained

The EVM organizes storage as an array of 2^256 slots, each exactly 32 bytes (256 bits). Understanding how variables map to these slots is essential for optimization and avoiding storage collisions.

🎯 Interactive: Storage Slot Calculator

Calculate how many slots your variables will use:

110
Variable Size
256 bits
32 bytes
Per Slot
1x
variables fit
Slots Needed
1
32 bytes
Efficiency
100.0%
0B wasted
Visual Layout:
Slot 0:
1
32/32B

How Storage Slots Work

Every state variable in Solidity is assigned a storage slot starting from slot 0. The EVM packs smaller variables into the same slot when possible, reading/writing entire 32-byte slots at once.

Storage Layout Rules:

1
Sequential Assignment
Variables are assigned slots in declaration order (0, 1, 2...)
2
Automatic Packing
Variables ≀32 bytes can share a slot if they fit together
3
No Splitting
Variables never span multiple slotsβ€”new slot starts if can't fit
4
Special Structures
Arrays/mappings use hash-based addressing for dynamic sizing

Layout Visualizer

Example Contract:

contract StorageExample {
  uint256 a;      // Slot 0 (32 bytes, fills entire slot)
  uint128 b;      // Slot 1 (16 bytes, leaves 16 bytes free)
  uint128 c;      // Slot 1 (16 bytes, packs with b)
  uint64 d;       // Slot 2 (8 bytes, new slot)
  uint64 e;       // Slot 2 (8 bytes, packs with d)
  uint64 f;       // Slot 2 (8 bytes, packs with d & e)
  address owner;  // Slot 2 (20 bytes, but won't fitβ€”goes to Slot 3)
  bool active;    // Slot 3 (1 byte, packs with owner)
}
Slot 0:
uint256 a (32 bytes)
Slot 1:
uint128 b
uint128 c
Slot 2:
uint64 d
uint64 e
uint64 f
unused (8B)
Slot 3:
address owner (20 bytes)
bool
unused (11B)
πŸ’‘ Key Observations:
  • β€’ b and c pack together (both uint128 = 32 bytes total)
  • β€’ d, e, f pack together (3Γ—uint64 = 24 bytes, leaving 8 unused)
  • β€’ owner (address = 20 bytes) can't fit in Slot 2, starts Slot 3
  • β€’ active (bool = 1 byte) packs with owner in Slot 3
  • β€’ Total: 4 slots used, 19 bytes wasted

Dynamic Data Structures

πŸ—ΊοΈ
Mappings

Values stored at: keccak256(key . slotNumber)

mapping(address => uint) balances; // Slot 0
// User balance at: keccak256(userAddr . 0)
πŸ“š
Arrays

Length at slot, elements at: keccak256(slotNumber) + index

uint[] items; // Slot 0 = length
// items[0] at: keccak256(0) + 0

⚠️ Storage Collision Warning

In upgradeable contracts, changing storage layout can cause catastrophic bugs:

❌ Wrong (V2):
uint256 newVar;  // Slot 0
uint256 balance; // Slot 1 (was 0!)
Balance data now points to wrong slot!
βœ… Correct (V2):
uint256 balance; // Slot 0 (unchanged)
uint256 newVar;  // Slot 1 (added)
Always append new variables!