Sui.

Post

Share your knowledge.

SuiLover.
Jul 30, 2025
Expert Q&A

What's the role of upgrade_cap in Sui packages?

I'm trying to understand this aspect of the Sui Network because I'm either building, debugging, or deploying something that touches this area. I want a detailed explanation of how this mechanism or feature works, along with relevant CLI usage, Move code structure, or architectural concepts. My goal is to gain enough clarity to apply this knowledge in a real project—whether that's a custom smart contract, an NFT system, a wallet integration, or a DeFi tool. The Sui Network has unique features compared to EVM chains, so I'm particularly interested in what sets it apart and how that affects development best practices. It would help to have sample code, command line examples, or typical errors to watch for, especially when using the Sui CLI, SDK, or deploying on localnet/testnet. Ultimately, I want to avoid common mistakes, follow the best security principles, and ensure that the functionality I’m working on behaves as expected under realistic conditions.

  • Sui
  • Transaction Processing
  • Move
7
12
Share
Comments
.

Answers

12
BigSneh.
Jul 30 2025, 12:16

The upgrade_cap in Sui packages is a special object that controls the authority to upgrade a published Move package. When you publish a package on Sui, the system creates an upgrade_cap object linked to that package. This object is held by the publisher or designated authority and is required to perform any future upgrades or modifications to the package code. Without the upgrade_cap, the package becomes immutable, meaning you cannot change or replace its modules. This design enforces secure, controlled upgrades and prevents unauthorized changes, which is crucial for maintaining trust and stability in deployed smart contracts.

From a CLI perspective, when you publish a package using sui client publish, you receive the package ID and the upgrade_cap object ID. To upgrade, you must sign a transaction referencing the current upgrade_cap, then the system issues a new version of the package along with a new upgrade_cap object. In Move code, you do not directly manipulate the upgrade_cap, but your deployment scripts or off-chain logic must handle it securely.

Architecturally, the upgrade_cap embodies ownership and permission control for package lifecycle management, distinguishing Sui's package model from Ethereum's immutable contracts or proxies. Best practice is to store the upgrade_cap securely offline or in a multisig wallet to prevent compromise. Also, careful version management and testing are needed before upgrading since it affects all users depending on the package.

Typical errors include losing the upgrade_cap, which locks you out of upgrades, or mismanaging the authority leading to security risks. Using the Sui CLI, you can query the current upgrade_cap for a package or submit upgrade transactions that consume and reissue it.

In summary, the upgrade_cap is the cryptographic key to package evolution on Sui, enabling controlled, permissioned upgrades while maintaining decentralization and security. Managing it properly is essential for production-ready Sui smart contract development and deployment workflows.

6
Best Answer
Comments
.
Paul.
Paul4180
Jul 31 2025, 05:27

In Sui, upgrade_cap is used to manage the upgradeability of smart contracts, allowing developers to update contracts without losing data. It grants permission to perform contract upgrades and is typically owned by a trusted address.

Key Points:

  • Control Upgrade: upgrade_cap ensures only authorized addresses can trigger upgrades.

  • Move Code: Used in Move modules to handle upgrades.

  • CLI Example:

    sui client publish --upgrade --package <package-id> --capability <upgrade-cap-id>
    

Best Practices:

  • Test upgrades on localnet/testnet.
  • Secure the upgrade_cap to prevent unauthorized access.
8
Comments
.
Ashford.
Jul 31 2025, 06:31

Role of upgrade_cap in Sui Network

Purpose: Controls who can upgrade a smart contract or module.

  • What it does: Grants upgrade permissions to specific addresses (usually admins). It ensures only authorized entities can modify deployed contracts.

Key Concepts:

  • Move Language: upgrade_cap is implemented in Move for secure contract management.
  • Deployment: Specified during contract deployment to allow future upgrades by authorized addresses only.

CLI Example:

sui client publish --gas-budget 10000 --upgrade-cap <upgrade-cap-id>

Example Move Code:

public fun grant_upgrade_cap() {
    let upgrade_cap = UpgradeCap::new();
    // Assign cap to authorized address
}

Common Issues:

  • Permission Errors: Unauthorized address trying to upgrade.
  • Missing Capabilities: Ensure upgrade_cap is set correctly during deployment.

Best Practices:

  • Restrict upgrade_cap: Limit access to trusted addresses.
  • Test in Localnet/Testnet: Ensure proper behavior before deploying to mainnet.
7
Comments
.
Benjamin XDV.
Jul 31 2025, 09:40

The upgrade_cap in Sui serves as an authorization mechanism for package upgrades, functioning as a unique capability object that grants upgrade rights to its holder. Unlike EVM chains where contracts are immutable, Sui's upgrade system requires this object to modify published packages, providing controlled mutability while maintaining security. The holder of the upgrade_cap can authorize upgrades via the sui client upgrade CLI command or programmatically through Move's package::authorize_upgrade function. Best practices involve securely storing the upgrade_cap (often in a Versioned or AdminCap wrapper) and implementing proper ownership controls, as losing it permanently locks upgradeability while exposing it risks unauthorized modifications.

6
Comments
.
theking.
Jul 30 2025, 11:17

In the Sui network, the upgrade_cap plays a critical role in enabling secure and controlled upgrades to Move packages after their initial deployment. When you publish a package on Sui, an object of type UpgradeCap is created and returned. This object is the sole authority that allows future upgrades to the package, effectively acting as a key that grants permission to change its code.

You must retain ownership of this upgrade_cap if you intend to upgrade your package later. If you transfer it to another address or burn it (e.g., by sending it to 0x0), then no further upgrades are possible. This design enforces immutability unless explicitly opted into by the package creator.

Why UpgradeCap Matters

Sui’s object-centric model introduces this concept to distinguish between immutable packages and upgradeable ones. Packages without access to their upgrade_cap are considered permanently immutable. This contrasts with EVM chains where contracts are mutable only if delegatecall proxies or upgradable patterns are built manually.

Upgrade Workflow Example

When you publish a package:

sui client publish --path . --gas-budget 100000000

The output includes:

  • Package ID
  • UpgradeCap object ID

To upgrade later:

sui client upgrade \
  --package <original_package_id> \
  --module-upgrade-path <new_module_path> \
  --upgrade-cap <upgrade_cap_id> \
  --gas-budget 100000000

Using UpgradeCap in Move

In your Move modules, you might protect upgrades or sensitive transitions using the capability object:

public entry fun secure_upgrade(upgrade_cap: &UpgradeCap, ctx: &mut TxContext) {
    // logic that uses upgrade_cap as proof of authority
}

Or destroy it if you want to finalize the package:

transfer::public_transfer(upgrade_cap, @0x0);

This permanently revokes your ability to update the package.

Best Practices

  • Store the upgrade_cap in a secure wallet or governance module if you plan future upgrades.
  • Burn the upgrade_cap if you want your package to be immutable, which is common for financial contracts or NFTs to build user trust.
  • Wrap upgrade logic in governance, so that a DAO or multisig approves upgrades instead of a single private key.
  • Avoid leaking the upgrade_cap ID, as possession equals authority in Sui.

Common Errors

  • Missing upgrade_cap during upgrade → Results in “permission denied” errors.
  • Accidental transfer to null → Your package becomes locked forever.
  • Trying to call upgrade on immutable packages → The system will reject the transaction.

Learn More

Ultimately, the upgrade_cap represents Sui's commitment to explicit authority and fine-grained control over state and code evolution. Understanding how to use, store, and revoke it is key to building secure and maintainable smart contracts in the Sui ecosystem.

5
Comments
.
Alya.
Alya-14
Jul 30 2025, 17:27

Role of upgrade_cap in Sui Packages

The upgrade_cap is a capability object that controls package upgrade permissions in Sui's object-centric upgrade system. Unlike EVM chains that use proxy patterns, Sui handles upgrades at the package level through this dedicated capability object.

Core Mechanics

When publishing a package:

sui client publish --gas-budget 100000000 --path ./move_package

The transaction returns:

  1. Package ID (immutable identifier)
  2. upgrade_cap object (0x2::package::UpgradeCap)

This capability object:

  • Is a first-class Sui object that can be owned, transferred, or shared
  • Must be included as an input in any upgrade transaction
  • Contains the package ID it authorizes upgrades for

Key Technical Details

  1. Security Model:

    • Only the owner of the upgrade_cap can upgrade the package
    • Follows Sui's object ownership model (no signer-based authorization)
    • Can be managed in multisig contracts or timelocks
  2. Upgrade Process:

    sui client upgrade --package [PACKAGE_ID] \
                      --upgrade-cap [UPGRADE_CAP_ID] \
                      --gas-budget 200000000 \
                      --path ./updated_package
    
  3. Critical Move Patterns:

    // Storing upgrade_cap in a publisher struct
    struct Publisher has key {
        id: UID,
        upgrade_cap: package::UpgradeCap,
    }
    
    // Upgrading (must use &mut reference)
    public entry fun upgrade(
        publisher: &mut Publisher,
        new_package: vector<u8>,
        new_modules: vector<vector<u8>>,
        ctx: &mut TxContext
    ) {
        package::upgrade_package(
            &mut publisher.upgrade_cap,
            new_package,
            new_modules,
            ctx
        )
    }
    

Sui-Specific Advantages vs EVM

  • No proxy patterns needed: Upgrades happen at the package level, not contract level
  • Backward compatibility: Existing objects remain valid after upgrades
  • Capability-based security: Uses Sui's object ownership model instead of admin roles
  • Transparent governance: The upgrade_cap can be put in multisigs or DAO treasuries

Common Errors & Solutions

ErrorCauseFix
UpgradeCap not foundMissing capability objectVerify you're using the correct upgrade_cap ID
Package ID mismatchUsing wrong upgrade_capCheck package::id(&cap) matches target package
Insufficient gasUpgrade requires more gasIncrease gas budget (upgrades cost 2-3x regular tx)
Module compatibility errorBreaking changes in new versionEnsure struct layouts remain compatible

Best Practices

  1. For production: Transfer upgrade_cap to a multisig wallet
  2. For immutable contracts: Burn the capability after publishing
  3. Always validate capability ownership: object::is_owner(&cap, tx_context::sender(ctx))
  4. Emit events on upgrades: event::emit(UpgradeEvent { package_id, version })

The upgrade_cap embodies Sui's object-oriented security model - upgrade permissions are treated as transferable assets rather than hardcoded admin roles, providing flexible governance options while maintaining security.

5
Comments
.
290697tz.
Jul 30 2025, 12:18

The upgrade_cap in Sui is a special object that represents the authority to upgrade a published Move package. When you publish a package using the Sui CLI, the system automatically creates an upgrade_cap object associated with that package. This object controls the ability to upgrade or modify the package after its initial deployment. Without holding the upgrade_cap, no one can upgrade the package, making it immutable.

For example, when publishing a package:

sui client publish --gas-budget 10000 --path ./my_package

The output includes the upgrade_cap object ID. This object must be included in upgrade transactions to prove authority. To upgrade the package, you call:

sui client upgrade --package <new_package_path> --upgrade-cap <upgrade_cap_object_id> --gas-budget 10000

This transaction consumes the old upgrade_cap and issues a new one for the upgraded package. The upgrade_cap enforces strict permission control on the package lifecycle, ensuring only authorized parties can modify the contract code.

From a Move perspective, the package code itself doesn't directly manipulate the upgrade_cap because it is handled at the protocol level. However, developers need to manage this object securely off-chain, typically storing it in secure wallets or multisig setups to prevent unauthorized upgrades.

A lost upgrade_cap means you cannot upgrade the package again, effectively locking the code forever. This emphasizes the importance of secure key management practices. Moreover, upgrading a package impacts all users relying on it, so upgrades should be thoroughly tested on testnet or localnet before deployment.

Because Sui packages are versioned, the upgrade_cap is the key to moving between versions. The system guarantees atomic upgrades by tying the package versioning to this capability.

You can query the upgrade_cap associated with a package using the Sui CLI or SDK:

sui client get-package <package_id>

which returns package details including the current upgrade_cap. Handling the upgrade_cap securely is part of best practices in Sui development workflows to avoid accidental or malicious code changes.

In contrast to Ethereum’s immutable contracts or proxy upgrade patterns, Sui's upgrade_cap is an explicit on-chain capability object controlling upgrades. This design enhances transparency and security by making upgrade authority an explicit object in the system.

Developers must incorporate the upgrade_cap management into their deployment pipelines, typically scripting the upgrade process to include the upgrade_cap object and ensuring it is signed by the correct keys.

4
Comments
.
shamueely.
Jul 30 2025, 11:30

The upgrade_cap in Sui packages is a special object that gives its owner the exclusive right to upgrade a published Move package. When you deploy a package on the Sui network, Sui generates an UpgradeCap object tied to your account. This capability acts as a secure access key—without it, no one (including you) can upgrade that package’s code in the future.

You use the upgrade_cap when calling the upgrade function provided by Sui’s system module. The CLI allows you to perform upgrades like this:

sui client upgrade \
  --package-path /path/to/your/package \
  --upgrade-capability <upgrade_cap_object_id> \
  --gas-budget 100000000

You must pass the ID of the UpgradeCap object to authorize the upgrade transaction. If you lose the UpgradeCap or transfer it to an inaccessible address (such as 0x0), the package becomes immutable because no one can initiate an upgrade.

If you want to deliberately disable future upgrades, you can include a function in your package like:

public entry fun burn_cap(cap: UpgradeCap) {
    sui::package::delete_upgrade_cap(cap);
}

Calling this function deletes the capability and locks the code forever. This is recommended for packages that must be trustless or governed externally.

Best practice: Always secure your UpgradeCap and consider transferring it to a DAO or multisig if you're working on collaborative or public infrastructure.

3
Comments
.
Arnold.
Arnold2956
Jul 31 2025, 08:13

Role of upgrade_cap in Sui Packages

The upgrade_cap is a capability object that grants permission to upgrade a Move package on Sui. It’s a unique Sui feature that enables controlled mutability for published packages, unlike immutable contracts on EVM chains.


Key Concepts

  1. What It Does:

    • Holds the Publisher and UpgradePolicy (e.g., immutable, compatible, arbitrary).
    • Required to authorize package upgrades (e.g., bug fixes, new features).
  2. Why Sui Is Unique:

    • EVM contracts are immutable after deployment; Sui allows upgrades with governance (via upgrade_cap).
    • Upgrades are gas-efficient (only modified modules are re-published).
  3. Security Implications:

    • Whoever holds the upgrade_cap can change the package’s logic.
    • Best practice: Transfer it to a multisig or DAO after deployment.

Move Code Structure

1. Defining upgrade_cap in init

module my_pkg::my_module {
  use sui::package;
  use sui::transfer;

  // Called once during package publish
  fun init(otw: &mut TxContext) {
    let (upgrade_cap, publisher) = package::claim(otw);
    transfer::transfer(upgrade_cap, tx_context::sender(otw)); // Give cap to deployer
  }
}

2. Upgrading a Package

module my_pkg::upgrader {
  use sui::package;

  // Requires the UpgradeCap
  public entry fun upgrade(
    upgrade_cap: &mut UpgradeCap,
    new_package: vector<u8>,
    otw: &mut TxContext
  ) {
    package::upgrade(upgrade_cap, new_package, otw);
  }
}
3
Comments
.
Evgeniy CRYPTOCOIN.
Jul 31 2025, 09:07

upgrade_cap in Sui is a key object that controls package upgrades.

Key Points:

  1. Admin Rights – Only the upgrade_cap holder can upgrade the package.
  2. Security – Prevents unauthorized changes (unlike Ethereum’s immutable contracts).
  3. CLI Usage – Required for sui client upgrade.

Move Example:

struct UpgradeCap has key, store { id: UID }  

Best Practices:

✔ Store securely (e.g., multisig).
✔ Test upgrades on localnet first.

Why Unique:
Sui allows upgrades (vs EVM immutability).

(Losing upgrade_cap = no more upgrades!)

3
Comments
.
Bekky.
Bekky1752
Jul 31 2025, 10:03

1. Core Concept

The upgrade_cap is a privileged object that controls package upgrades in Sui. Unlike EVM chains where contracts are immutable, Sui allows controlled mutability through this capability-based system.

2. Key Properties

PropertyDescription
OwnerOnly the holder can authorize upgrades
TransferableCan be sent to other addresses
BurnablePermanent immutability option

2. Move Implementation

Basic Structure

module my_pkg::admin {
    use sui::package;
    use sui::transfer;
    use sui::tx_context;

    // Generated during initial publish
    struct UpgradeCap has key, store { 
        id: UID 
    }

    // Initialize and transfer cap
    public fun init(ctx: &mut tx_context::TxContext) {
        let (upgrade_cap, publisher) = package::claim_upgrade_cap(ctx);
        transfer::transfer(upgrade_cap, tx_context::sender(ctx));
    }
}

Upgrade Flow

module my_pkg::upgrader {
    use sui::package;
    use sui::upgrade_cap;

    public entry fun upgrade(
        cap: &mut upgrade_cap::UpgradeCap,
        policy: u8,
        digest: vector<u8>,
        ctx: &mut tx_context::TxContext
    ) {
        package::authorize_upgrade(cap, policy, digest);
        let new_pkg = package::make_upgrade_ticket(cap, policy, digest);
        // ... complete upgrade
    }
}

3. CLI Workflow

Initial Publish

sui client publish --gas-budget 1000000000
# Output includes UpgradeCap object ID

Authorize Upgrade

sui client call \
  --package <UPGRADE_CAP_PKG> \
  --module admin \
  --function authorize_upgrade \
  --args <UPGRADE_CAP_ID> 1 0x<COMPILED_PACKAGE_DIGEST> \
  --gas-budget 1000000000

Execute Upgrade

sui client upgrade --upgrade-capability <UPGRADE_CAP_ID> \
  --gas-budget 1000000000

4. Security Patterns

Capability Nesting

struct AdminCap has key {
    id: UID,
    upgrade_cap: UpgradeCap  // Delegatable
}

Time-Locked Upgrades

module my_pkg::timelock {
    struct TimedUpgradeCap has key {
        cap: UpgradeCap,
        unlock_epoch: u64
    }

    public fun upgrade_when_ready(
        cap: &mut TimedUpgradeCap,
        ctx: &mut TxContext
    ) {
        assert!(tx_context::epoch(ctx) >= cap.unlock_epoch, ELOCKED);
        package::authorize_upgrade(&mut cap.cap, ...);
    }
}

5. Common Pitfalls

ErrorSolution
MissingUpgradeCapStore cap ID in your deployment docs
UnauthorizedUpgradeUse transfer::freeze_object to lock caps
DigestMismatchRecompile with identical dependencies

6. Upgrade Policies

// Bitflags determining upgrade flexibility
const POLICY_COMPATIBLE: u8 = 0x1;  // Backwards-compatible
const POLICY_ADDITIVE: u8  = 0x2;   // New functions only
const POLICY_BREAKING: u8 = 0x4;    // Full changes

7. Testing Strategy

Localnet Dry-Run

sui client publish --upgrade-policy 7 --dry-run

Upgrade Simulation

#[test_only]
module test {
    fun test_upgrade() {
        let (cap, _) = package::test_upgrade_cap();
        package::authorize_upgrade(&mut cap, ...);
        assert!(package::test_is_authorized(cap), 0);
    }
}

Architectural Impact

  1. Decentralized Governance:

    • DAOs can hold upgrade caps
    • Multi-sig schemes via shared objects
  2. Enterprise Readiness:

    • Staged rollouts with policy flags
    • Emergency revocation capabilities
  3. DevEx Advantages:

    • Fix bugs post-deployment
    • Gas-efficient storage migrations

For production systems:

1
Comments
.
24p30p.
24p30p2042
Jul 30 2025, 15:46

In Sui, the upgrade_cap is a special object that gives you the right to upgrade a published Move package. When you deploy a package with --upgradeable, you automatically get an UpgradeCap object linked to it. This object acts like a permission slip—without it, you can't push upgrades to that package. You need to hold and sign with this object anytime you want to upgrade the code, which makes it a powerful access control mechanism for on-chain development.

This design makes Sui different from EVM chains, where upgrade logic is often handled through proxy contracts and separate admin roles. In Sui, the upgrade permission is baked into the object system. If you're building an NFT collection, DeFi contract, or any system that needs future updates, the UpgradeCap ensures that only the trusted developer (or multisig) with that cap can push those changes, reducing the chance of unauthorized upgrades.

To create an upgradeable package, use the Sui CLI:

sui client publish --path . --gas-budget 100000000 --with-unpublished-dependencies --upgradeable

Once published, you’ll see an upgrade_cap in the output like this:

"createdObjects": [
  {
    "objectType": "0x2::package::UpgradeCap",
    "objectId": "0xabc123...",
    ...
  }
]

To upgrade the package later, compile it to a .json digest and run:

sui client upgrade --package-id <PACKAGE_ID> --module <PATH_TO_COMPILED_MODULE> --upgrade-capability <CAP_OBJECT_ID> --gas-budget 100000000

Make sure the object ID in --upgrade-capability matches the one you got from the first publish. If you lose this object or forget to protect it (like by transferring to a multisig wallet), anyone who gets it can modify your contract.

Common mistakes include forgetting to store the upgrade_cap, using an invalid digest, or trying to upgrade a non-upgradeable package. Best practice is to vault the upgrade_cap securely, especially in production, and monitor it closely during audits.

You can read more about upgrade_cap and secure package upgrades in Sui’s official docs: https://docs.sui.io/build/package-upgrades

-1
Comments
.

Do you know the answer?

Please log in and share it.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

637Posts1665Answers
Sui.X.Peera.

Earn Your Share of 1000 Sui

Gain Reputation Points & Get Rewards for Helping the Sui Community Grow.

Reward CampaignAugust