What are the key, store, copy and drop abilities in Move?
November 4, 2026
Abilities are permissions you declare on a struct with has. They control what the compiler lets you do with values of that type. copy lets a value be duplicated. drop lets it be discarded or go out of scope. store lets it be kept inside other values in on-chain storage. key makes it a top-level storage item, which on Sui means an object, and an object's first field must be id: UID. A struct with no abilities can only be created, moved and unpacked by its own module.
Declaring abilities
module example::abilities;
use std::string::String;
/// Plain data: can be copied, dropped and stored.
public struct Point has copy, drop, store { x: u64, y: u64 }
/// Can live inside an object but can't be copied or dropped.
public struct Metadata has store { bio: String }
/// An object. Only this module can transfer it.
public struct Profile has key {
id: UID,
metadata: Metadata,
}
/// An object anyone can transfer or wrap.
public struct Badge has key, store { id: UID }
/// No abilities: a "hot potato" that must be consumed in the same transaction.
public struct Receipt { amount: u64 }What each ability means in practice
copy: you can write let b = a; and keep using a. Without copy, assigning a value moves it. This is what prevents duplicating coins or NFTs. It almost always comes with drop; a value you can copy but not discard forces you to use every copy.
drop: the value may be ignored or go out of scope. Without it, the compiler makes you consume the value explicitly, by unpacking it, passing it on or storing it. Types without drop give you the hot potato pattern, where a value must be returned to a specific function before the transaction can finish.
store: the value can be a field of an object, or be stored in a dynamic field. On an object (key, store) it also does two more things:
- The object can be wrapped inside another object.
- Any module can transfer, share or freeze it with
transfer::public_transfer,public_share_objectandpublic_freeze_object.
key: the type is an object. The Sui verifier requires the first field to be id: UID, and the compiler requires every field to have store. Because UID has only store, an object can never have copy or drop.
key vs key + store
This choice affects your API:
public fun mint_profile(ctx: &mut TxContext): Profile {
Profile { id: object::new(ctx), metadata: Metadata { bio: b"".to_string() } }
}
// Only this module can do this, because Profile lacks `store`:
public fun send_profile(p: Profile, to: address) {
transfer::transfer(p, to)
}transfer::transfer<T: key> may only be called from the module that defines T, which the bytecode verifier enforces. transfer::public_transfer<T: key + store> works from anywhere, including a PTB's TransferObjects command. Leave out store when you want transfers to go through your own rules, such as soulbound tokens or Kiosk transfer policies. Add it for freely tradable assets like Coin<T>, which is declared has key, store.
Rules worth remembering
- A struct can only have abilities that all of its fields have. For generic types the abilities are conditional:
vector<T>andOption<T>havecopyonly ifTdoes. - Built-in types (integers,
bool,address,vector) havecopy,dropandstore. References havecopyanddrop, but notstore. UIDhas onlystore, andIDhascopy,dropandstore. Store anIDwhen you want to point to another object.- Generic constraints use the same names:
fun f<T: key + store>(x: T). For type parameters used only as markers, see What are generics and phantom types in Move?.
Common errors
- Missing
drop: the compiler rejects a value that goes out of scope without being consumed. Transfer it, return it, or unpack it. - Invalid object struct: the Sui verifier rejects a
keystruct whose first field isn'tid: UID. - Transfer outside the defining module: if the type lacks
store,public_transferwon't compile. Call the module's own transfer function instead.
For more on objects, see What is an object on Sui? and What kinds of object ownership does Sui have?.
Sources
- Abilities: Introduction, The Move Book
- Ability: Key and Ability: Store, The Move Book
transfer.moveandobject.move, Sui framework source