Skip to main content
Abilities in Move are constraints on types that control what operations can be performed on them. They’re fundamental to Move’s resource safety guarantees.

The Four Abilities

copy

Type can be copied by value

drop

Type can be safely discarded

store

Type can be stored inside structs

key

Type can be a top-level object

Copy Ability

Types with copy can be duplicated:
public struct Point has copy, drop {
    x: u64,
    y: u64,
}

let p1 = Point { x: 1, y: 2 };
let p2 = p1;  // OK: Point has copy
let p3 = p1;  // Still OK: p1 is still valid
Objects with UID cannot have copy ability because UIDs must be unique.

Drop Ability

Types with drop can be ignored or discarded:
public struct Config has drop {
    timeout: u64,
}

let config = Config { timeout: 100 };
// config automatically dropped at end of scope

// Without drop, must explicitly unpack:
public struct NoDropStruct {
    value: u64,
}

let nds = NoDropStruct { value: 10 };
let NoDropStruct { value: _ } = nds;  // Must unpack

Store Ability

Types with store can be:
  • Stored in other structs
  • Transferred with public_transfer
  • Stored in global storage
public struct Container has key {
    id: UID,
    item: Item,  // Item must have store
}

public struct Item has store {
    value: u64,
}

Key Ability

Types with key can be top-level Sui objects:
public struct MyObject has key {
    id: UID,  // Required for key
    data: vector<u8>,
}

public struct NotAnObject has store {
    value: u64,  // No key = not an object
}
Types with key must have id: UID as their first field.

Common Combinations

// Transferable object
public struct NFT has key, store {
    id: UID,
    name: String,
}

transfer::public_transfer(nft, recipient);

Ability Constraints in Generics

// Require specific abilities
public struct Box<T: store> has key, store {
    id: UID,
    value: T,  // T must have store
}

public fun transfer_box<T: key + store>(box: Box<T>, recipient: address) {
    transfer::public_transfer(box, recipient);
}

Phantom Type Parameters

public struct Coin<phantom T> has key, store {
    id: UID,
    balance: u64,
}

// T doesn't need any abilities because it's phantom
public struct USD {}  // No abilities needed
let coin: Coin<USD> = /* ... */;

Best Practices

Only grant abilities that are necessary:
// If it doesn't need to be copied, don't add copy
public struct Asset has key, store {  // Not copy
    id: UID,
    value: u64,
}
// Bad: Assets should be unique
public struct Token has key, store, copy {
    id: UID,
    amount: u64,
}

// Good: Assets are unique
public struct Token has key, store {
    id: UID,
    amount: u64,
}

Move Overview

Learn Move basics

Objects

Understand Sui objects

Ownership

Object ownership rules

Build docs developers (and LLMs) love