# Storage, Memory, Calldata and Transient Storage — Blockchain & Smart Contracts (Solidity)

Source: https://www.geekswithgeeks.com/en/solidity/d-location

> Choose data locations correctly and understand their costs.

## Where data lives

Reference types need a **data location**. **`storage`** is persistent contract state on chain; reading and especially writing it is the most expensive operation (a new non-zero slot costs about 20,000 gas). **`memory`** is temporary, exists for the duration of a call and is cleared afterwards. **`calldata`** is the read-only input data of an external call, the cheapest location for array and string parameters you do not modify. Assignments behave differently by location: `Item storage item = items[i];` creates a **reference**, so changes write to storage, while `Item memory item = items[i];` makes a **copy**, so changes are lost unless written back, a classic bug. The **stack** holds value-type local variables (limited to 16 reachable slots, which is the origin of "stack too deep" errors). Storage is organised in **32-byte slots**, and adjacent small variables are **packed** into one slot. **Transient storage** (EIP-1153, active since the Cancun upgrade in 2024) is cleared at the end of each transaction and is cheap; recent Solidity versions support the `transient` keyword for value types, useful for reentrancy locks.

## Data locations

Storage persists across transactions; memory and calldata exist only during a call.

![Three containers side by side: a heavy safe labelled with a chain icon, a whiteboard that gets wiped, and a sealed read-only envelope.](assets/figures/solidity/section-3-map.svg) — Figure 3.1 — Storage, memory and calldata.

## Storage references versus memory copies

A common bug and its fix.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Inventory {
    struct Item {
        string sku;
        uint128 stock;
        uint128 priceWei;
    }

    Item[] public items;

    function add(string calldata sku, uint128 stock, uint128 priceWei) external {
        items.push(Item(sku, stock, priceWei));   // calldata string copied into storage
    }

    // BUG: modifies a memory copy; storage is unchanged
    function restockBroken(uint256 index, uint128 amount) external {
        Item memory item = items[index];
        item.stock += amount;
    }

    // FIX: a storage reference writes through to contract state
    function restock(uint256 index, uint128 amount) external {
        Item storage item = items[index];
        item.stock += amount;
    }

    // calldata avoids copying a large array we only read
    function totalStock(uint256[] calldata indexes) external view returns (uint256 total) {
        for (uint256 i = 0; i < indexes.length; i++) {
            total += items[indexes[i]].stock;
        }
    }
}
// stock and priceWei (uint128 each) pack into a single 32-byte storage slot
```

## Read storage once

Each storage read costs gas. In loops or repeated checks, copy a storage value into a local variable once (`uint256 bal = balances[user];`), work with it, and write the result back once.

**Quiz:** What does `Item memory item = items[i]; item.stock += 1;` do to contract storage?

- [x] Nothing: it changes a temporary memory copy
- [ ] Increments the stored stock
- [ ] Deletes the item
- [ ] Reverts the transaction

*Answer:* Nothing: it changes a temporary memory copy. Memory variables are copies; use a storage reference to modify state.
