Package Upgrades & Compatibility

37.1 Sui upgrades

Publishing returns an UpgradeCap. An upgrade publishes a new package at a new address, linked to the original; existing objects keep their original type IDs (types are always identified by the package that first defined them).

Compatible (default) Change implementations; add modules, functions, structs; change non-public functions

Only add new code; cannot change existing implementations package::only_additive_upgrades(&mut cap) Only change dependencies package::only_dep_upgrades(&mut cap)

Policies can only become more restrictive. You can also wrap the UpgradeCap in a custom object (multisig, time-lock, DAO vote) to govern upgrades.

sui client upgrade --upgrade-capability 0xUPGRADE_CAP

37.2 Compatibility rules (both chains, simplified)

Change body of any function Yes (Sui compatible policy; Aptos compatible) Add new module / function / struct

Change or remove a public function signature Change/remove public(package)/friend/private functions

Change a non-public entry function signature Add, remove, reorder, or retype struct fields Add or remove struct abilities

Change type parameter constraints of public items Add enum variants Aptos: append allowed; Sui: no

37.3 Versioned shared objects (Sui)

Old package versions remain callable forever. To force users onto new logic, store a version in shared objects:

New fields can be added later via dynamic fields keyed on the object's UID.

const VERSION: u64 = 2;
const EWrongVersion: u64 = 0;

public struct Pool has key { id: UID, version: u64, /* ... */ }

public fun swap(pool: &mut Pool /* ... */) {
    assert!(pool.version == VERSION, EWrongVersion);
    // ...
}

/// Called once after the upgrade by the admin
public fun migrate(_: &AdminCap, pool: &mut Pool) {
    assert!(pool.version < VERSION, EWrongVersion);
    pool.version = VERSION;
}

37.4 Aptos upgrades

On Aptos, re-publishing to the same address upgrades in place (aptos move publish again). upgrade_policy in Move.toml is compatible (default) or immutable; a package's policy can only get stricter, and dependencies must have an equal or stricter policy. Because code is upgraded in place, all callers see the new logic immediately; init_module runs only for newly added modules.