Reclaim storage and staked NEAR
Reclaim NEAR storage staking: remove entries to unlock balance, clear collections safely, free old state after migrations, and delete test accounts.
Intermediate4 min read3-question check
Storage stake is not spent, only locked, so every byte you delete releases 10¹⁹ yoctoNEAR back into the account’s available balance. That balance belongs to the account that held the data, usually the contract. If a user paid for the bytes, returning their share is your code’s job, not the protocol’s.
Delete entries and refund the payer#
// the Notes contract from "Make users pay for their storage"
#[near]
impl Notes {
pub fn delete_note(&mut self) -> Promise {
let who = env::predecessor_account_id();
let initial = env::storage_usage();
require!(self.notes.remove(&who).is_some(), "no note to delete");
// removals are buffered too: flush before measuring
self.notes.flush();
let freed = initial.saturating_sub(env::storage_usage());
let refund = env::storage_byte_cost().saturating_mul(freed as u128);
Promise::new(who).transfer(refund)
}
}Clearing whole collections#
| Operation | Work done | Notes |
|---|---|---|
remove(&key) | One storage removal | The normal, bounded way to free data |
clear() on IterableMap, IterableSet or Vector | One removal per entry | Fine for small collections; on large ones it runs out of gas, so remove in capped batches instead |
LookupMap / LookupSet | No clear() | They keep no list of keys. You must know the keys, from your own index or an off-chain indexer, and remove them one by one |
| Dropping the field in an upgrade | Nothing | The entries stay in storage under the old prefix, still locking NEAR, until you remove them |
Migrations: free the old state#
An upgrade changes code, not state. A migrate method marked #[init(ignore_state)] reads the old layout with env::state_read::<OldState>() and returns the new struct. If the new version no longer needs a collection, removing the field is not enough: delete its entries (in batches if there are many) or they keep locking NEAR forever. Migration is also the moment to move a large inline Vec or HashMap into a store collection and shrink the root record.
- Smaller code releases stake too. Deploying a smaller Wasm unlocks the difference in code size (1 NEAR per 100 KB).
- Delete test and dev accounts you no longer need. near-cli’s
account delete-accountcommand sends the remaining balance, including released storage stake, to a beneficiary account you choose. - Clear state before deleting an account. The protocol refuses to delete an account whose state, not counting contract code, exceeds 10,000 bytes (
DeleteAccountWithLargeState). - Withdraw what is now available. Released stake sits on the contract account as ordinary balance; move it out with a transfer if it is not needed there.
Check yourself
3 questions · progress saved in this browser