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_CAP37.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.