Aptos gas profiling: how to reduce execution costs
Gas costs on Aptos are determined by the bytecode instructions your Move module executes, the storage it writes to, and the size of the data it touches. Reducing execution costs means writing Move code that does less work per transaction, avoids unnecessary writes, and uses Aptos-specific features like aggregators and objects designed for cheap updates. You profile gas usage with the Aptos CLI's move test --gas-report flag, then refactor the hot spots.
Understanding aptos gas components
Aptos charges gas in three categories:
- Execution gas - per bytecode instruction executed.
- IO gas - per byte read from or written to storage.
- Storage gas - per byte of data stored permanently.
Most cost surprises come from IO and storage gas, not execution. A loop that runs 200 iterations might cost 0.001 APT in execution but trigger 0.01 APT in IO gas if each iteration reads a different resource. Profiling tells you which category dominates.
How to Generate a Gas Report
- Install the Aptos CLI if you haven't already. Run
aptos --versionto confirm it's present. - Navigate to your Move project - the directory containing
Move.toml. - Run the gas test command:
aptos move test --gas-reportThis compiles and runs all tests, then prints a table per test function showing: - Total gas units used.
- Breakdown by execution, IO, and storage.
-
Number of storage reads and writes.
-
Look for functions with high IO or storage costs. A function that reads 50 resources per call is a candidate for redesign.
Common Cost Patterns and How to Fix Them
Redundant Reads
If your function reads the same resource multiple times, cache it in a local variable. Each move_from or borrow_global costs IO gas. Example:
// Expensive: reads twice
let a = move_from<Counter>(addr);
let b = borrow_global<Counter>(addr);
// Cheaper: read once
let a = move_from<Counter>(addr);
let b = &a;
Unnecessary Writes
Every move_to and move_from followed by a store writes to storage. If a value hasn't changed, don't write it. Use borrow_global_mut only when you intend to modify, and avoid writing back unchanged data.
Using aggregators for counters
If you need to increment a counter, use an Aggregator instead of a regular integer stored in a resource. Aggregators batch updates and charge less storage gas per increment. The Aptos framework provides aptos_std::aggregator_v2.
use aptos_std::aggregator_v2::Aggregator;
struct CounterHolder has key {
counter: Aggregator,
}
Aggregators are ideal for leaderboards, view counts, or any value that changes frequently.
Minimize Vector Operations
Vectors in Move are cheap for small sizes but become expensive to iterate or clone as they grow. If your function processes a vector of 1000 elements, each element access costs execution gas and may trigger bounds checks. Consider:
- Passing only a slice or index range instead of the full vector.
- Using
for_eachorfilterfromstd::vectorif available, rather than manual loops. - Storing large vectors off-chain and referencing them by hash.
Batch Writes
If you must update multiple resources, do it in one transaction. The gas cost of a single transaction that writes 5 resources is lower than 5 separate transactions, because each transaction pays a base execution cost and a signature verification cost.
Using the gas schedule
Aptos publishes its gas schedule as an on-chain resource. You can query it with:
aptos move view --function-id 0x1::gas_schedule::get_gas_schedule
This returns per-instruction costs in gas units. If you see an instruction with a high cost (for example, ED25519_VERIFY at several thousand units), minimize its use. Verify signatures once and cache results.
Testing Gas Changes
After refactoring, run aptos move test --gas-report again and compare the totals. A successful optimization reduces total gas units for the same logical operation. If gas increases, the refactor introduced extra work - revert or try a different approach.
When gas optimization matters
Gas optimization is worth your time when:
- Your dApp processes high transaction volumes (hundreds per day or more).
- Users pay for gas directly and complain about costs.
- A function is called in a loop or from many other functions.
For a simple NFT mint that runs once per user, the default gas cost is usually acceptable. Focus on the hot paths.
Tools and References
- The Aptos CLI gas report is the primary profiling tool. No third-party gas analyzer is widely maintained.
- The Aptos Move book includes a chapter on gas optimization in its "Advanced Topics" section. Check the official Aptos documentation for the latest gas schedule values.
- Community forums and the Aptos Discord
#move-developerschannel contain real-world examples of gas reduction patterns. Search for "gas report" or "aggregator" to find discussions.
Not financial advice. suiboxer.xyz publishes market data and general information about digital assets. Crypto assets are volatile and you can lose everything you put in. Nothing here is a recommendation to buy, sell or hold, and we make no price predictions.
Prices are sourced from third parties and may be delayed or wrong. Verify anything you intend to act on against a primary source.