
Top 10 Best Practices for Gas Optimization in Ethereum Smart Contracts
TechFlow Selected TechFlow Selected

Top 10 Best Practices for Gas Optimization in Ethereum Smart Contracts
By following these practices, developers can reduce gas consumption in smart contracts, lower transaction costs, and build more efficient and user-friendly applications.
Author: Certik
Gas fees on the Ethereum mainnet have long been a persistent issue, especially noticeable during periods of network congestion. At peak times, users often need to pay extremely high transaction fees. Therefore, optimizing Gas consumption during smart contract development is particularly important. Optimizing Gas usage not only effectively reduces transaction costs but also enhances transaction efficiency, delivering a more economical and efficient blockchain experience for users.
This article outlines the Gas fee mechanism of the Ethereum Virtual Machine (EVM), core concepts related to Gas optimization, and best practices for optimizing Gas fees when developing smart contracts. We hope this content provides inspiration and practical guidance for developers, while also helping regular users better understand how EVM Gas fees work—enabling us all to collectively address challenges within the blockchain ecosystem.
Introduction to the EVM Gas Fee Mechanism
In EVM-compatible networks, "Gas" refers to the unit used to measure the computational effort required to execute specific operations.
The diagram below illustrates the structure of the EVM. Here, Gas consumption is divided into three parts: operation execution, external message calls, and memory and storage read/write operations.

Source: Ethereum.org [1]
Since every transaction requires computational resources, a fee is charged to prevent infinite loops and denial-of-service (DoS) attacks. The cost required to complete a transaction is known as the "Gas fee."
Since the implementation of EIP-1559 (the London hard fork), the Gas fee has been calculated using the following formula:
Gas fee = units of gas used * (base fee + priority fee)
The base fee is burned, while the priority fee serves as an incentive for validators to include the transaction in a block. Setting a higher priority fee increases the likelihood that a transaction will be included in the next block—similar to a “tip” paid by the user to validators.
1. Understanding Gas Optimization in the EVM
When a Solidity smart contract is compiled, it is converted into a series of "opcodes."
Each opcode (e.g., contract creation, message calls, accessing account storage, or executing operations on the virtual machine) has a defined Gas cost, documented in the Ethereum Yellow Paper [2].

Following multiple EIP updates, the Gas costs of some opcodes have been adjusted and may differ from those listed in the Yellow Paper. For up-to-date information on opcode costs, refer to [3].
2. Fundamental Concepts of Gas Optimization
The core idea behind Gas optimization is to prioritize cost-efficient operations on EVM-based blockchains and avoid expensive ones.
The following operations are relatively low-cost in the EVM:
-
Reading and writing memory variables
-
Reading constant and immutable variables
-
Reading and writing local variables
-
Reading calldata variables, such as calldata arrays and structs
-
Internal function calls
High-cost operations include:
-
Reading and writing state variables stored in contract storage
-
External function calls
-
Looping operations
Best Practices for EVM Gas Fee Optimization
Based on the above fundamentals, we present a checklist of best practices for Gas optimization tailored for the developer community. By following these guidelines, developers can reduce Gas consumption in their smart contracts, lower transaction costs, and build more efficient and user-friendly applications.
1. Minimize Storage Usage
In Solidity, Storage is a limited resource and consumes significantly more Gas than Memory. Every time a smart contract reads from or writes to storage, it incurs high Gas costs.
According to the Ethereum Yellow Paper, storage operations cost over 100 times more than memory operations. For example, the opcodes mload and mstore consume only 3 Gas units, whereas storage operations like sload and sstore require at least 100 units even under optimal conditions.

Strategies to limit storage usage include:
-
Storing non-permanent data in memory
-
Reducing the number of storage modifications: keep intermediate results in memory and assign the final result to a storage variable after all computations are complete.
2. Variable Packing
The number of Storage slots used in a smart contract and how developers represent data significantly impact Gas consumption.
The Solidity compiler packs consecutive storage variables during compilation, using 32-byte storage slots as the basic unit. Variable packing involves strategically arranging variables so that multiple variables fit into a single storage slot.
The left side shows a less efficient implementation consuming 3 storage slots; the right side shows a more efficient one.

With this simple adjustment, developers can save 20,000 Gas units (since storing a new unused slot costs 20,000 Gas), now requiring only two storage slots.
Since each storage slot consumes Gas, variable packing optimizes Gas usage by reducing the total number of required slots.
3. Optimize Data Types
A variable can be represented using various data types, each with different operational costs. Choosing appropriate data types helps optimize Gas usage.
For instance, integers in Solidity can be subdivided into sizes such as uint8, uint16, uint32, etc. Since the EVM operates in 256-bit units, using uint8 forces the EVM to convert it to uint256—an operation that consumes additional Gas.

The code comparison above shows the Gas cost difference between uint8 and uint256. The UseUint() function uses 120,382 Gas, while UseUInt8() uses 166,111 Gas.
Alone, uint256 is cheaper than uint8. However, this changes if variable packing (as previously suggested) is applied. If four uint8 variables are packed into a single storage slot, iterating them becomes cheaper overall than handling four uint256 variables. This allows the contract to read/write one storage slot and move all four uint8 values to/from memory/storage in a single operation.
4. Use Fixed-size Variables Instead of Dynamic Ones
If data can fit within 32 bytes, use bytes32 instead of bytes or strings. Generally, fixed-size variables consume less Gas than variable-size ones. When possible, choose the smallest size from bytes1 to bytes32 based on required length.


5. Mappings vs Arrays
Data lists in Solidity can be implemented using either arrays or mappings, which differ significantly in syntax and structure.
Mappings are generally more efficient and less costly, while arrays support iteration and data packing. Therefore, prefer mappings when managing data lists unless iteration is needed or Gas savings can be achieved via data packing.
6. Use Calldata Instead of Memory
Function parameters can be declared in calldata or memory. The key difference is that memory variables can be modified within the function, whereas calldata is immutable.
Rule of thumb: if a function parameter is read-only, use calldata instead of memory to avoid unnecessary copying from calldata to memory.
Example 1: Using memory

When using the memory keyword, array values are copied from encoded calldata to memory during ABI decoding. This code block costs 3,694 Gas units.
Example 2: Using calldata

Directly reading from calldata skips the intermediate memory step. This optimization reduces execution cost to just 2,413 Gas units—a 35% improvement in Gas efficiency.
7. Use Constant/Immutable Keywords Whenever Possible
Constant and immutable variables are not stored in contract storage. They are computed at compile time and embedded directly into the contract bytecode, making access much cheaper than storage reads. Use these keywords wherever feasible.
8. Use Unchecked When Overflow/Underflow Is Impossible
When developers are certain that arithmetic operations won't cause overflow or underflow, they can use the unchecked keyword introduced in Solidity v0.8.0 to skip redundant checks and save Gas.
In the example below, the condition i < length ensures that i can never overflow. Since length is defined as uint256, the maximum value of i is max(uint256)-1. Thus, incrementing i inside an unchecked block is safe and more Gas-efficient.

Additionally, starting from version 0.8.0, the SafeMath library is no longer needed, as the compiler includes built-in overflow and underflow protection.
9. Optimize Modifiers
Modifier code is inlined into the functions they modify, meaning it is duplicated each time the modifier is used. This increases bytecode size and Gas consumption. One way to optimize this is shown below:
Before optimization:

After optimization:

In this case, refactoring the logic into an internal function _checkOwner() allows reuse within modifiers, reducing bytecode size and lowering Gas costs.
10. Short-Circuit Optimization
For || and && operators, logical expressions undergo short-circuit evaluation—if the first condition determines the outcome, the second is not evaluated.
To optimize Gas usage, place low-cost conditions first, potentially skipping expensive evaluations.
Additional General Recommendations
1. Remove Unused Code
Delete any unused functions or variables in your contract. This is the most straightforward way to reduce deployment costs and keep contract size small.
Practical tips:
Use the most efficient algorithms. Eliminate redundant calculations if their results are directly used. Essentially, remove any computation that isn't necessary.
Ethereum offers Gas refunds for freeing up storage space. When a variable is no longer needed, use the delete keyword or set it to its default value.
Loop optimization: avoid expensive loop operations, merge loops where possible, and move repeated computations outside the loop body.
2. Use Precompiled Contracts
Precompiled contracts provide complex library functions such as cryptographic and hashing operations. Since they run locally on client nodes rather than on the EVM, they require less Gas. Using precompiled contracts reduces computational workload and saves Gas.
Examples include ECDSA (Elliptic Curve Digital Signature Algorithm) and SHA2-256 hash functions. By leveraging these in smart contracts, developers can lower Gas costs and improve application performance.
For a full list of precompiled contracts supported on Ethereum, see [4].
3. Use Inline Assembly
Inline assembly enables developers to write low-level, highly efficient code that runs directly on the EVM, avoiding costly Solidity opcodes. It allows finer control over memory and storage usage, further reducing Gas fees. Additionally, inline assembly supports complex operations difficult or impossible to implement purely in Solidity, offering greater flexibility for Gas optimization.
Below is an example showing Gas savings through inline assembly:

As shown, the second approach using inline assembly achieves higher Gas efficiency compared to the standard method.
However, inline assembly introduces risks and is error-prone. It should be used cautiously and only by experienced developers.
4. Use Layer 2 Solutions
Layer 2 solutions reduce the amount of data that needs to be stored and processed on the Ethereum mainnet.
Solutions like rollups, sidechains, and state channels offload transaction processing from the main Ethereum chain, enabling faster and cheaper transactions.
By batching numerous transactions, these solutions reduce the number of on-chain transactions, thereby lowering Gas fees. Layer 2 adoption also improves Ethereum’s scalability, allowing more users and applications to participate without causing network congestion.
5. Use Optimization Tools and Libraries
Several optimization tools are available, including the solc optimizer, Truffle's build optimizer, and Remix's Solidity compiler.

These tools help minimize bytecode size, eliminate dead code, and reduce the number of operations required to execute a smart contract. Combined with Gas optimization libraries like "solmate," developers can effectively reduce Gas costs and enhance contract efficiency.
Conclusion
Optimizing Gas consumption is a crucial step for developers aiming to minimize transaction costs and improve the efficiency of smart contracts on EVM-compatible networks. By prioritizing cost-effective operations, minimizing storage usage, leveraging inline assembly, and following the best practices discussed in this article, developers can significantly reduce Gas consumption.
However, caution is essential during optimization to avoid introducing security vulnerabilities. While optimizing code and reducing Gas costs, the inherent security of smart contracts must never be compromised.
[1]: https://ethereum.org/en/developers/docs/gas/
[2]: https://ethereum.github.io/yellowpaper/paper.pdf
[3]: https://www.evm.codes/
[4]: https://www.evm.codes/precompiled
Join TechFlow official community to stay tuned
Telegram:https://t.me/TechFlowDaily
X (Twitter):https://x.com/TechFlowPost
X (Twitter) EN:https://x.com/BlockFlow_News














