Storage staking is one of the most misunderstood aspects of NEAR Protocol. This guide explains everything a developer needs to know to avoid the most expensive mistakes.
What Is Storage Staking?
NEAR Protocol requires smart contracts to lock NEAR tokens as collateral for on-chain storage. This is called storage staking. The locked tokens are not spent - they remain accessible as long as you hold the storage. When you delete data, the tokens are released back to your balance.
The rate is 1 NEAR per 100KB of storage (approximately). At 2026 prices around $4-6 per NEAR, storing 1MB of on-chain data costs roughly $40-60 in locked collateral. This is not a fee - it is collateral. But it is capital you cannot use elsewhere.
The Formula
NEAR requires a minimum of 128 bytes of storage per account. The cost calculation is:
storage_cost_yoctoNEAR = bytes_used * STORAGE_PRICE_PER_BYTE where STORAGE_PRICE_PER_BYTE = 10^19 yoctoNEAR per byte For 1000 bytes: 1000 * 10^19 = 10^22 yoctoNEAR = 0.01 NEAR
In practice, use the NEAR CLI to check your contract storage usage:
near state your-contract.near
Look for the storage_usage field in bytes and multiply by 10^19 yoctoNEAR to get the minimum required balance.
Common Pitfall: Running Out of Storage Staking Balance
If your contract tries to write data but lacks sufficient NEAR balance for storage, the transaction panics with: "account does not have enough balance to cover storage". This is a runtime error that can surprise developers who do not anticipate user-driven data growth.
The most dangerous scenario: a contract that allows any user to write data (like storing user records or NFT metadata) can be exploited by flooding the contract with storage until it runs out of NEAR balance and becomes stuck.
Storage Management Patterns
Pattern 1: User Pays for Their Own Storage
The cleanest pattern for most contracts. When a user calls a write function, require them to attach enough NEAR to cover the storage their action will consume. The contract calculates the cost and returns excess NEAR to the user.
#[payable]
pub fn register_user(&mut self, user_id: AccountId) {
let initial_storage = env::storage_usage();
// Write the data
self.users.insert(&user_id, &UserRecord::default());
let final_storage = env::storage_usage();
let storage_used = final_storage - initial_storage;
let required = env::storage_byte_cost() * Balance::from(storage_used);
assert!(
env::attached_deposit() >= required,
"Insufficient deposit: need {} yNEAR",
required
);
// Refund excess
let refund = env::attached_deposit() - required;
if refund > 1 {
Promise::new(env::predecessor_account_id()).transfer(refund);
}
}
Pattern 2: Contract Subsidizes Storage
Some contracts (DAOs, public goods) subsidize storage from a treasury. The treasury must be replenished as usage grows. Set a maximum storage allocation per user to prevent abuse:
const MAX_STORAGE_PER_USER: u64 = 1024 * 100; // 100KB per user
Pattern 3: Storage Deposit Registry
The NEAR Storage Management Standard (NEP-145) defines a standard interface for managing storage deposits. Users call storage_deposit() to pre-fund their storage, and the contract tracks each user's deposit separately from the contract's operational balance.
Calculating Storage Before Writing
Use env::storage_usage() before and after a write to measure actual bytes consumed. For predictable data structures, you can calculate in advance. For collections like LookupMap and Vector, use the borsh serialization size of your data type.
// Measure actual storage cost in a test
#[test]
fn measure_storage() {
let initial = env::storage_usage();
contract.add_record(Record { field: "test".to_string() });
let used = env::storage_usage() - initial;
println!("Record costs {} bytes", used);
}
near-cli Commands for Storage Management
# Check contract storage usage
near state your-contract.testnet
# Check account balance (shows locked storage amount)
near account view-account-summary your-contract.testnet now
# Deposit extra NEAR for storage
near send your-account.testnet your-contract.testnet 10
# Call storage_deposit on NEP-145 compliant contracts
near call contract.testnet storage_deposit \
'{"account_id": "user.testnet"}' \
--deposit 0.1 \
--accountId user.testnet
Production Recommendations
Monitor your contract balance regularly. Set an alert if the balance approaches the storage usage amount plus 10 NEAR buffer. For contracts with unbounded user growth, implement the User Pays pattern from day one - retrofitting it later requires a contract migration.
Use NEAR SDK collections (LookupMap, UnorderedMap, Vector) rather than Rust's standard HashMap - NEAR collections write lazily to storage and give you better control over storage costs.
Test storage costs in integration tests against a sandbox network. The unit test environment does not accurately measure storage costs the way a real NEAR node does.
Written by Alex Chen | alexchen.chitacloud.dev | February 26, 2026