# Solidity gas optimization: 16 patterns we use on audits

> Storage slot packing, unchecked math, calldata over memory, custom errors, immutable vs constant: 16 gas-saving patterns that land 15-40% cuts in our audits.

We audited 11 Solidity codebases in 2025. Every single one had 15-40% avoidable gas cost, mostly in the same patterns. Here they are in order of impact.

## 1 · Pack storage slots

A `uint256` and a `bool` in separate slots cost 20k gas per write. Pack them into one slot (`uint128 + bool + address`) and the second write is a few hundred gas. Look for structs with mixed-size fields.

## 2 · Custom errors over require strings

`require(x, "NotOwner")` deploys the string to bytecode. `error NotOwner(); revert NotOwner();` is ~50 bytes smaller and costs less at runtime.

```solidity
// before
require(msg.sender == owner, "NotOwner");

// after
error NotOwner();
if (msg.sender != owner) revert NotOwner();
```

## 3 · `calldata` over `memory` for read-only params

External function arrays/structs: use `calldata` unless you mutate. Saves the copy + a chunk of stack.

## 4 · `unchecked` on safe arithmetic

Solidity 0.8+ checks every math op. Where you've already proven no overflow (post-condition from a prior `require`, or a bounded loop counter), wrap in `unchecked { ... }` for significant gas savings.

## 5 · `immutable` > `constant` for computed-once values

`immutable` is cheaper to read than `constant` when the value is computed at construction (like `owner = msg.sender`). `constant` wins only for literals.

## 6 · Short-circuit loops

`for (uint i; i < n; ++i)` beats `i++` (pre-increment saves a few gas per iter). Cache `n` if it's a storage read. If the work can stop early, `break` · don't run the full loop.

## 7 · Events for historical state

Every `SSTORE` is ~20k gas. An `emit` is ~1.5k. If data doesn't need on-chain reads - historical logs, UI feeds, analytics - use events, not storage.

> Run forge snapshot before and after each change. Measure, don't guess · a 'clever' optimization can cost gas via bytecode bloat.

## 8-16 · The shortlist

- Use `>=` instead of `>` when semantically equivalent (saves 3 gas).
- `++` costs less than `+= 1` (same reason).
- Cache storage reads in a local variable for loops.
- Use `assembly { mstore(0x40, ...) }` for hot paths only · readability cost is real.
- Prefer `type(uint256).max` over hardcoded max values.
- `transfer`/`send` are gas-stipended · `call{value: ...}` is cheaper and more flexible.
- Batch similar ops into one function to share the function-selector jump cost.
- `external` functions are cheaper than `public` when not called internally.
- Avoid double-SSTORE on initialization · use `immutable` where possible.

## The anti-pattern

Don't optimize gas before you've got correctness + audit. A gas-optimized contract that reverts under edge conditions is a catastrophe, not a win. Correctness first, then gas · in that order.

## What to take away

- The 16 gas-optimization patterns we apply on every audit, ranked by real-world impact. 15-40% reductions typical on contracts that haven't been gas-reviewed.

## Tags

Blockchain, Solidity, Gas, Optimization, Audit

## We build this for clients

https://dfieldsolutions.com/en/services/blockchain

## More from the lab

- https://dfieldsolutions.com/en/lab/smart-contract-security-checklist-2026.md — The 2026 smart contract security checklist before you ship
- https://dfieldsolutions.com/en/lab/foundry-invariant-testing-patterns-2026.md — Foundry invariant testing · patterns we use on every audit
- https://dfieldsolutions.com/en/lab/smart-contract-audit-checklist.md — Smart contract audit checklist · the one we actually use
- https://dfieldsolutions.com/en/lab/smart-contract-audit-cost-2026.md — Smart contract audit pricing in 2026: €4k vs €15k vs €60k

---

Source: https://dfieldsolutions.com/en/lab/solidity-gas-optimization-patterns-2026
DField Solutions — Torony köz 5-1.a, 2120 Dunakeszi, Hungary — +36 20 722 0002 — dezso@dfieldsolutions.com
Booking: see https://dfieldsolutions.com/en/contact
