Gas is a tax on every interaction, and small design choices compound into big savings.

Start with storage: reads and writes to storage dominate cost, so pack related values into a single slot, prefer memory for temporary work, and cache repeated storage reads in local variables. Use immutable and constant for values fixed at deploy time — they live in bytecode, not storage.

Loops are the next trap. Avoid unbounded loops over user-controlled arrays; bound them, or switch to pull-based patterns where each user claims their own share. Emit events instead of storing data you only need off-chain.

Finally, measure. A gas snapshot in your test suite turns optimization from guesswork into a ratchet — every change either lowers the number or it doesn't ship. Safety always wins over a few thousand gas, but disciplined patterns usually give you both.