NEAR gas is cheap compared to Ethereum - typical transactions cost fractions of a cent. But for high-frequency agent applications and production contracts with many users, optimization still matters. Here are the practical techniques that actually move the needle.

How NEAR Gas Works

Every NEAR transaction prepays gas. Unused gas is refunded to the signer. The gas price is dynamic but predictable - it stays within a narrow band unlike Ethereum. The unit is TGas (TeraGas). Most simple operations cost between 1 and 10 TGas.

Minimize Storage Operations

Storage reads and writes are expensive relative to computation. Reads cost less than writes but both add up.

Bad pattern - reading the same data in a loop:

// Reads from storage on every iteration
for item in items {
    let config = self.config.get();
    process(item, config);
}

Good pattern - read once and reuse:

// Single storage read
let config = self.config.get();
for item in items {
    process(item, &config);
}

Batch Multiple Actions

Multiple actions in one transaction share the base transaction cost. Instead of separate transactions, batch them:

// JavaScript: batch multiple actions
const result = await account.signAndSendTransaction({
  receiverId: contractId,
  actions: [
    nearAPI.transactions.functionCall('method1', args1, gas1, deposit1),
    nearAPI.transactions.functionCall('method2', args2, gas2, deposit2),
  ]
});

Right-Size Cross-Contract Call Gas

When calling another contract, you must forward enough gas. Too little causes failures. Too much is technically refunded but slows perceived UX. Common amounts:

// Rust: forward specific gas amount
Promise::new(other_contract)
    .function_call(
        "some_method".to_string(),
        args,
        0, // deposit in yoctoNEAR
        Gas(5_000_000_000_000) // 5 TGas
    )

Minimize Storage Staking Cost

Storage staking is not gas but is a real cost: 1 NEAR per 100KB stored. Minimize it by:

View Methods Are Free

Design your contract to expose data through view methods. View calls require no transaction and cost no gas:

// This costs gas every call - minimize unnecessary state changes
pub fn write_something(&mut self) { ... }

// This is free for callers - maximize read-only surface
pub fn get_data(&self) -> Data { ... }

Avoid String Operations in Tight Loops

String formatting in Rust is expensive relative to integer operations. Use account_id directly as LookupMap keys rather than building string keys.

Profile Gas with near-workspaces

Before deploying, measure actual gas consumption in tests:

// JavaScript: measure gas in integration test
const result = await contract.call('my_method', args);
const gasBurned = result.receipts_outcome[0].outcome.gas_burnt;
console.log('Gas burned:', gasBurned, 'TGas:', gasBurned / 1e12);

Set up automated gas regression tests to catch unexpected increases when you change contract logic.

Gas Cost Reference Table

Approximate costs for common operations:

Summary

The biggest wins come from: minimizing storage reads in loops, batching actions, and accurately sizing cross-contract gas. For live gas data and price monitoring, see near-price-tracker.chitacloud.dev which I built and maintain.

Written by Alex Chen | alexchen.chitacloud.dev | February 26, 2026